/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "OverView.h" #include "SampleCode.h" #include "SkCanvas.h" #include "SkView.h" static const char gIsOverview[] = "is-overview"; static int to_lower(int c) { if ('A' <= c && c <= 'Z') { c = c - 'A' + 'a'; } return c; } static void make_lc(SkString* str) { char* ptr = str->writable_str(); while (*ptr) { *ptr = to_lower(*ptr); ptr += 1; } } static bool case_insensitive_find(const SkString& base, const SkString& sub) { SkString lcBase(base); SkString lcSub(sub); make_lc(&lcBase); make_lc(&lcSub); return lcBase.find(lcSub.c_str()) >= 0; } static bool draw_this_name(const SkString& name, const SkString& filter) { if (filter.isEmpty()) { return true; } return case_insensitive_find(name, filter); } class OverView : public SkView { public: OverView(int count, const SkViewFactory* factories[]); ~OverView() override; protected: bool onEvent(const SkEvent&) override; bool onQuery(SkEvent* evt) override { if (SampleCode::TitleQ(*evt)) { SampleCode::TitleR(evt, "Overview"); return true; } if (evt->isType(gIsOverview)) { return true; } SkUnichar uni; if (SampleCode::CharQ(*evt, &uni)) { if (uni >= ' ') { fMatchStr.appendUnichar(uni); } this->inval(nullptr); return true; } return this->INHERITED::onQuery(evt); } void onDraw(SkCanvas* canvas) override; bool onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) override { return false; } Click* onFindClickHandler(SkScalar cx, SkScalar cy, unsigned modi) override { const SkRect crect = SkRect::MakeXYWH(cx - 0.5f, cy - 0.5f, 1, 1); SkPoint loc = this->start(); for (int i = 0; i < fCount; ++i) { if (draw_this_name(fNames[i], fMatchStr)) { if (this->bounds(loc).intersects(crect)) { SkEvent evt("set-curr-index"); evt.setFast32(i); this->sendEventToParents(evt); break; } this->next(&loc); } } return nullptr; } private: int fCount; const SkViewFactory** fFactories; SkString* fNames; SkString fMatchStr; SkPaint fNamePaint; SkPaint::FontMetrics fNameMetrics; SkScalar fNameW; SkScalar fNameH; SkRect bounds(const SkPoint& loc) const { return SkRect::MakeXYWH(loc.x(), loc.y() + fNameMetrics.fAscent, fNameW, fNameH); } SkPoint start() const { return SkPoint::Make(10, -fNameMetrics.fTop); } void next(SkPoint* loc) const { loc->fY += fNameH; if (loc->fY > this->height() - fNameMetrics.fBottom) { loc->fY = -fNameMetrics.fTop; loc->fX += fNameW; } } typedef SkView INHERITED; }; SkView* create_overview(int count, const SkViewFactory* factories[]) { return new OverView(count, factories); } bool is_overview(SkView* view) { SkEvent isOverview(gIsOverview); return view->doQuery(&isOverview); } OverView::OverView(int count, const SkViewFactory* factories[]) { fCount = count; fFactories = factories; fNames = new SkString[count]; for (int i = 0; i < count; ++i) { SkView* view = (*fFactories[i])(); if (view) { (void)SampleCode::RequestTitle(view, &fNames[i]); if (0 == fNames[i].find("GM:")) { fNames[i].remove(0, 3); } } } fNamePaint.setAntiAlias(true); fNamePaint.setTextSize(12); fNameW = 160; fNameH = fNamePaint.getFontMetrics(&fNameMetrics); } OverView::~OverView() { delete[] fNames; } bool OverView::onEvent(const SkEvent& evt) { return this->INHERITED::onEvent(evt); } void OverView::onDraw(SkCanvas* canvas) { SkPaint paint; paint.setColor(0xFFF8F8F8); canvas->drawPaint(paint); SkPoint loc = this->start(); for (int i = 0; i < fCount; ++i) { if (draw_this_name(fNames[i], fMatchStr)) { canvas->drawRect(this->bounds(loc), paint); canvas->drawString(fNames[i], loc.x(), loc.y(), fNamePaint); this->next(&loc); } } }