1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "OverView.h" 9 #include "SampleCode.h" 10 #include "SkCanvas.h" 11 #include "SkView.h" 12 13 static const char gIsOverview[] = "is-overview"; 14 15 static int to_lower(int c) { 16 if ('A' <= c && c <= 'Z') { 17 c = c - 'A' + 'a'; 18 } 19 return c; 20 } 21 22 static void make_lc(SkString* str) { 23 char* ptr = str->writable_str(); 24 while (*ptr) { 25 *ptr = to_lower(*ptr); 26 ptr += 1; 27 } 28 } 29 30 static bool case_insensitive_find(const SkString& base, const SkString& sub) { 31 SkString lcBase(base); 32 SkString lcSub(sub); 33 make_lc(&lcBase); 34 make_lc(&lcSub); 35 return lcBase.find(lcSub.c_str()) >= 0; 36 } 37 38 static bool draw_this_name(const SkString& name, const SkString& filter) { 39 if (filter.isEmpty()) { 40 return true; 41 } 42 return case_insensitive_find(name, filter); 43 } 44 45 class OverView : public SkView { 46 public: 47 OverView(int count, const SkViewFactory* factories[]); 48 ~OverView() override; 49 50 protected: 51 bool onEvent(const SkEvent&) override; 52 bool onQuery(SkEvent* evt) override { 53 if (SampleCode::TitleQ(*evt)) { 54 SampleCode::TitleR(evt, "Overview"); 55 return true; 56 } 57 if (evt->isType(gIsOverview)) { 58 return true; 59 } 60 SkUnichar uni; 61 if (SampleCode::CharQ(*evt, &uni)) { 62 if (uni >= ' ') { 63 fMatchStr.appendUnichar(uni); 64 } 65 this->inval(nullptr); 66 return true; 67 } 68 return this->INHERITED::onQuery(evt); 69 } 70 71 void onDraw(SkCanvas* canvas) override; 72 73 bool onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) override { 74 return false; 75 } 76 77 Click* onFindClickHandler(SkScalar cx, SkScalar cy, unsigned modi) override { 78 const SkRect crect = SkRect::MakeXYWH(cx - 0.5f, cy - 0.5f, 1, 1); 79 SkPoint loc = this->start(); 80 for (int i = 0; i < fCount; ++i) { 81 if (draw_this_name(fNames[i], fMatchStr)) { 82 if (this->bounds(loc).intersects(crect)) { 83 SkEvent evt("set-curr-index"); 84 evt.setFast32(i); 85 this->sendEventToParents(evt); 86 break; 87 } 88 this->next(&loc); 89 } 90 } 91 return nullptr; 92 } 93 94 private: 95 int fCount; 96 const SkViewFactory** fFactories; 97 SkString* fNames; 98 SkString fMatchStr; 99 SkPaint fNamePaint; 100 SkPaint::FontMetrics fNameMetrics; 101 SkScalar fNameW; 102 SkScalar fNameH; 103 104 SkRect bounds(const SkPoint& loc) const { 105 return SkRect::MakeXYWH(loc.x(), loc.y() + fNameMetrics.fAscent, fNameW, fNameH); 106 } 107 108 SkPoint start() const { 109 return SkPoint::Make(10, -fNameMetrics.fTop); 110 } 111 112 void next(SkPoint* loc) const { 113 loc->fY += fNameH; 114 if (loc->fY > this->height() - fNameMetrics.fBottom) { 115 loc->fY = -fNameMetrics.fTop; 116 loc->fX += fNameW; 117 } 118 } 119 120 typedef SkView INHERITED; 121 }; 122 123 SkView* create_overview(int count, const SkViewFactory* factories[]) { 124 return new OverView(count, factories); 125 } 126 127 bool is_overview(SkView* view) { 128 SkEvent isOverview(gIsOverview); 129 return view->doQuery(&isOverview); 130 } 131 132 OverView::OverView(int count, const SkViewFactory* factories[]) { 133 fCount = count; 134 fFactories = factories; 135 136 fNames = new SkString[count]; 137 for (int i = 0; i < count; ++i) { 138 SkView* view = (*fFactories[i])(); 139 if (view) { 140 (void)SampleCode::RequestTitle(view, &fNames[i]); 141 if (0 == fNames[i].find("GM:")) { 142 fNames[i].remove(0, 3); 143 } 144 } 145 } 146 147 fNamePaint.setAntiAlias(true); 148 fNamePaint.setTextSize(12); 149 fNameW = 160; 150 fNameH = fNamePaint.getFontMetrics(&fNameMetrics); 151 } 152 153 OverView::~OverView() { 154 delete[] fNames; 155 } 156 157 bool OverView::onEvent(const SkEvent& evt) { 158 return this->INHERITED::onEvent(evt); 159 } 160 161 void OverView::onDraw(SkCanvas* canvas) { 162 SkPaint paint; 163 paint.setColor(0xFFF8F8F8); 164 canvas->drawPaint(paint); 165 166 SkPoint loc = this->start(); 167 for (int i = 0; i < fCount; ++i) { 168 if (draw_this_name(fNames[i], fMatchStr)) { 169 canvas->drawRect(this->bounds(loc), paint); 170 canvas->drawText(fNames[i].c_str(), fNames[i].size(), loc.x(), loc.y(), fNamePaint); 171 this->next(&loc); 172 } 173 } 174 } 175