| epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 1 | |
| 2 | /* |
| 3 | * Copyright 2011 Google Inc. |
| 4 | * |
| 5 | * Use of this source code is governed by a BSD-style license that can be |
| 6 | * found in the LICENSE file. |
| 7 | */ |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 8 | #include "SkWidget.h" |
| 9 | #include "SkCanvas.h" |
| 10 | #include "SkInterpolator.h" |
| 11 | #include "SkTime.h" |
| 12 | #include "SkParsePaint.h" |
| 13 | |
| 14 | #if 0 |
| 15 | SkWidgetView::SkWidgetView(U32 flags) : SkView(flags) |
| 16 | { |
| 17 | } |
| 18 | |
| 19 | SkWidgetView::~SkWidgetView() |
| 20 | { |
| 21 | } |
| 22 | |
| 23 | const char* SkWidgetView::GetEventType() |
| 24 | { |
| 25 | return "SkWidgetView"; |
| 26 | } |
| 27 | |
| 28 | ///////////////////////////////////////////////////////////////////////////// |
| 29 | ///////////////////////////////////////////////////////////////////////////// |
| 30 | |
| 31 | class SkTextView::Interp { |
| 32 | public: |
| 33 | Interp(const SkString& old, SkMSec now, SkMSec dur, AnimaDir dir) : fOldText(old), fInterp(1, 2) |
| 34 | { |
| 35 | SkScalar x = 0; |
| 36 | fInterp.setKeyFrame(0, now, &x, 0); |
| 37 | x = SK_Scalar1; |
| 38 | if (dir == kBackward_AnimDir) |
| 39 | x = -x; |
| 40 | fInterp.setKeyFrame(1, now + dur, &x); |
| 41 | } |
| 42 | bool draw(SkCanvas* canvas, const SkString& newText, SkScalar x, SkScalar y, SkPaint& paint) |
| 43 | { |
| 44 | SkScalar scale; |
| 45 | |
| 46 | if (fInterp.timeToValues(SkTime::GetMSecs(), &scale) == SkInterpolator::kFreezeEnd_Result) |
| 47 | { |
| 48 | canvas->drawText(newText.c_str(), newText.size(), x, y, paint); |
| 49 | return false; |
| 50 | } |
| 51 | else |
| 52 | { |
| 53 | U8 alpha = paint.getAlpha(); |
| 54 | SkScalar above, below; |
| deanm@chromium.org | 1599a43 | 2009-06-04 15:37:11 +0000 | [diff] [blame] | 55 | (void)paint.measureText(NULL, 0, &above, &below); |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 56 | SkScalar height = below - above; |
| 57 | SkScalar dy = SkScalarMul(height, scale); |
| 58 | if (scale < 0) |
| 59 | height = -height; |
| 60 | |
| 61 | // draw the old |
| 62 | paint.setAlpha((U8)SkScalarMul(alpha, SK_Scalar1 - SkScalarAbs(scale))); |
| 63 | canvas->drawText(fOldText.c_str(), fOldText.size(), x, y - dy, paint); |
| 64 | // draw the new |
| 65 | paint.setAlpha((U8)SkScalarMul(alpha, SkScalarAbs(scale))); |
| 66 | canvas->drawText(newText.c_str(), newText.size(), x, y + height - dy, paint); |
| 67 | // restore the paint |
| 68 | paint.setAlpha(alpha); |
| 69 | return true; |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | private: |
| 74 | SkString fOldText; |
| 75 | SkInterpolator fInterp; |
| 76 | }; |
| 77 | |
| deanm@chromium.org | 1599a43 | 2009-06-04 15:37:11 +0000 | [diff] [blame] | 78 | SkTextView::SkTextView(U32 flags) : SkView(flags), fInterp(NULL), fDoInterp(false) |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 79 | { |
| 80 | fMargin.set(0, 0); |
| 81 | } |
| 82 | |
| 83 | SkTextView::~SkTextView() |
| 84 | { |
| 85 | delete fInterp; |
| 86 | } |
| 87 | |
| 88 | void SkTextView::getText(SkString* str) const |
| 89 | { |
| 90 | if (str) |
| 91 | str->set(fText); |
| 92 | } |
| 93 | |
| 94 | void SkTextView::setText(const char text[], AnimaDir dir) |
| 95 | { |
| 96 | if (!fText.equals(text)) |
| 97 | { |
| 98 | SkString tmp(text); |
| 99 | this->privSetText(tmp, dir); |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | void SkTextView::setText(const char text[], size_t len, AnimaDir dir) |
| 104 | { |
| 105 | if (!fText.equals(text)) |
| 106 | { |
| 107 | SkString tmp(text, len); |
| 108 | this->privSetText(tmp, dir); |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | void SkTextView::setText(const SkString& src, AnimaDir dir) |
| 113 | { |
| 114 | if (fText != src) |
| 115 | this->privSetText(src, dir); |
| 116 | } |
| 117 | |
| 118 | void SkTextView::privSetText(const SkString& src, AnimaDir dir) |
| 119 | { |
| 120 | SkASSERT(fText != src); |
| 121 | |
| 122 | if (fDoInterp) |
| 123 | { |
| 124 | if (fInterp) |
| 125 | delete fInterp; |
| 126 | fInterp = new Interp(fText, SkTime::GetMSecs(), 500, dir); |
| 127 | } |
| 128 | fText = src; |
| deanm@chromium.org | 1599a43 | 2009-06-04 15:37:11 +0000 | [diff] [blame] | 129 | this->inval(NULL); |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 130 | } |
| 131 | |
| 132 | ///////////////////////////////////////////////////////////////// |
| 133 | |
| 134 | void SkTextView::getMargin(SkPoint* margin) const |
| 135 | { |
| 136 | if (margin) |
| 137 | *margin = fMargin; |
| 138 | } |
| 139 | |
| 140 | void SkTextView::setMargin(const SkPoint& margin) |
| 141 | { |
| 142 | if (fMargin != margin) |
| 143 | { |
| 144 | fMargin = margin; |
| deanm@chromium.org | 1599a43 | 2009-06-04 15:37:11 +0000 | [diff] [blame] | 145 | this->inval(NULL); |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 146 | } |
| 147 | } |
| 148 | |
| 149 | void SkTextView::onDraw(SkCanvas* canvas) |
| 150 | { |
| 151 | this->INHERITED::onDraw(canvas); |
| 152 | |
| 153 | if (fText.size() == 0) |
| 154 | return; |
| 155 | |
| 156 | SkPaint::Align align = fPaint.getTextAlign(); |
| 157 | SkScalar x, y; |
| 158 | |
| 159 | switch (align) { |
| 160 | case SkPaint::kLeft_Align: |
| 161 | x = fMargin.fX; |
| 162 | break; |
| 163 | case SkPaint::kCenter_Align: |
| 164 | x = SkScalarHalf(this->width()); |
| 165 | break; |
| 166 | default: |
| 167 | SkASSERT(align == SkPaint::kRight_Align); |
| 168 | x = this->width() - fMargin.fX; |
| 169 | break; |
| 170 | } |
| 171 | |
| deanm@chromium.org | 1599a43 | 2009-06-04 15:37:11 +0000 | [diff] [blame] | 172 | fPaint.measureText(NULL, 0, &y, NULL); |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 173 | y = fMargin.fY - y; |
| 174 | |
| 175 | if (fInterp) |
| 176 | { |
| 177 | if (fInterp->draw(canvas, fText, x, y, fPaint)) |
| deanm@chromium.org | 1599a43 | 2009-06-04 15:37:11 +0000 | [diff] [blame] | 178 | this->inval(NULL); |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 179 | else |
| 180 | { |
| 181 | delete fInterp; |
| deanm@chromium.org | 1599a43 | 2009-06-04 15:37:11 +0000 | [diff] [blame] | 182 | fInterp = NULL; |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 183 | } |
| 184 | } |
| 185 | else |
| 186 | canvas->drawText(fText.c_str(), fText.size(), x, y, fPaint); |
| 187 | } |
| 188 | |
| 189 | ////////////////////////////////////////////////////////////////////////////////////// |
| 190 | |
| 191 | void SkTextView::onInflate(const SkDOM& dom, const SkDOM::Node* node) |
| 192 | { |
| 193 | this->INHERITED::onInflate(dom, node); |
| 194 | |
| 195 | const char* text = dom.findAttr(node, "text"); |
| 196 | if (text) |
| 197 | this->setText(text); |
| 198 | |
| 199 | SkPoint margin; |
| 200 | if (dom.findScalars(node, "margin", (SkScalar*)&margin, 2)) |
| 201 | this->setMargin(margin); |
| 202 | (void)dom.findBool(node, "do-interp", &fDoInterp); |
| 203 | |
| 204 | SkPaint_Inflate(&fPaint, dom, node); |
| 205 | } |
| 206 | |
| 207 | ////////////////////////////////////////////////////////////////////////////////////// |
| 208 | |
| 209 | SkSliderView::SkSliderView(U32 flags) : SkWidgetView(flags) |
| 210 | { |
| 211 | fValue = 0; |
| 212 | fMax = 0; |
| 213 | } |
| 214 | |
| 215 | static U16 actual_value(U16CPU value, U16CPU max) |
| 216 | { |
| 217 | return SkToU16(SkMax32(0, SkMin32(value, max))); |
| 218 | } |
| 219 | |
| 220 | void SkSliderView::setMax(U16CPU max) |
| 221 | { |
| 222 | if (fMax != max) |
| 223 | { |
| 224 | fMax = SkToU16(max); |
| 225 | if (fValue > 0) |
| deanm@chromium.org | 1599a43 | 2009-06-04 15:37:11 +0000 | [diff] [blame] | 226 | this->inval(NULL); |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 227 | } |
| 228 | } |
| 229 | |
| 230 | void SkSliderView::setValue(U16CPU value) |
| 231 | { |
| 232 | if (fValue != value) |
| 233 | { |
| 234 | U16 prev = actual_value(fValue, fMax); |
| 235 | U16 next = actual_value(value, fMax); |
| 236 | |
| 237 | fValue = SkToU16(value); |
| 238 | if (prev != next) |
| 239 | { |
| deanm@chromium.org | 1599a43 | 2009-06-04 15:37:11 +0000 | [diff] [blame] | 240 | this->inval(NULL); |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 241 | |
| 242 | if (this->hasListeners()) |
| 243 | { |
| 244 | SkEvent evt; |
| 245 | |
| 246 | evt.setType(SkWidgetView::GetEventType()); |
| 247 | evt.setFast32(this->getSinkID()); |
| 248 | evt.setS32("sliderValue", next); |
| 249 | this->postToListeners(evt); |
| 250 | } |
| 251 | } |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | #include "SkGradientShader.h" |
| 256 | |
| 257 | static void setgrad(SkPaint* paint, const SkRect& r) |
| 258 | { |
| 259 | SkPoint pts[2]; |
| 260 | SkColor colors[2]; |
| 261 | |
| 262 | #if 0 |
| 263 | pts[0].set(r.fLeft, r.fTop); |
| 264 | pts[1].set(r.fLeft + r.height(), r.fBottom); |
| 265 | #else |
| 266 | pts[0].set(r.fRight, r.fBottom); |
| 267 | pts[1].set(r.fRight - r.height(), r.fTop); |
| 268 | #endif |
| 269 | colors[0] = SK_ColorBLUE; |
| 270 | colors[1] = SK_ColorWHITE; |
| 271 | |
| deanm@chromium.org | 1599a43 | 2009-06-04 15:37:11 +0000 | [diff] [blame] | 272 | paint->setShader(SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kMirror_TileMode))->unref(); |
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 273 | } |
| 274 | |
| 275 | void SkSliderView::onDraw(SkCanvas* canvas) |
| 276 | { |
| 277 | this->INHERITED::onDraw(canvas); |
| 278 | |
| 279 | U16CPU value = SkMax32(0, SkMin32(fValue, fMax)); |
| 280 | |
| 281 | SkRect r; |
| 282 | SkPaint p; |
| 283 | |
| 284 | r.set(0, 0, this->width(), this->height()); |
| 285 | |
| 286 | p.setAntiAliasOn(true); |
| 287 | p.setStyle(SkPaint::kStroke_Style); |
| 288 | p.setStrokeWidth(SK_Scalar1); |
| 289 | r.inset(SK_Scalar1/2, SK_Scalar1/2); |
| 290 | canvas->drawRect(r, p); |
| 291 | |
| 292 | if (fMax) |
| 293 | { |
| 294 | SkFixed percent = SkFixedDiv(value, fMax); |
| 295 | |
| 296 | r.inset(SK_Scalar1/2, SK_Scalar1/2); |
| 297 | r.fRight = r.fLeft + SkScalarMul(r.width(), SkFixedToScalar(percent)); |
| 298 | p.setStyle(SkPaint::kFill_Style); |
| 299 | setgrad(&p, r); |
| 300 | canvas->drawRect(r, p); |
| 301 | } |
| 302 | |
| 303 | #if 0 |
| 304 | r.set(0, 0, this->width(), this->height()); |
| 305 | r.inset(SK_Scalar1, SK_Scalar1); |
| 306 | r.inset(r.width()/2, 0); |
| 307 | p.setColor(SK_ColorBLACK); |
| 308 | canvas->drawLine(*(SkPoint*)&r.fLeft, *(SkPoint*)&r.fRight, p); |
| 309 | #endif |
| 310 | } |
| 311 | |
| 312 | SkView::Click* SkSliderView::onFindClickHandler(SkScalar x, SkScalar y) |
| 313 | { |
| 314 | return new Click(this); |
| 315 | } |
| 316 | |
| 317 | bool SkSliderView::onClick(Click* click) |
| 318 | { |
| 319 | if (fMax) |
| 320 | { |
| 321 | SkScalar percent = SkScalarDiv(click->fCurr.fX + SK_Scalar1, this->width() - SK_Scalar1*2); |
| 322 | percent = SkMaxScalar(0, SkMinScalar(percent, SK_Scalar1)); |
| 323 | this->setValue(SkScalarRound(percent * fMax)); |
| 324 | return true; |
| 325 | } |
| 326 | return false; |
| 327 | } |
| 328 | |
| 329 | #endif |
| 330 | |