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 
to_lower(int c)15 static int to_lower(int c) {
16     if ('A' <= c && c <= 'Z') {
17         c = c - 'A' + 'a';
18     }
19     return c;
20 }
21 
make_lc(SkString * str)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 
case_insensitive_find(const SkString & base,const SkString & sub)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 
draw_this_name(const SkString & name,const SkString & filter)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     virtual ~OverView();
49 
50 protected:
51     bool onEvent(const SkEvent&) override;
onQuery(SkEvent * evt)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             fMatchStr.appendUnichar(uni);
63             this->inval(NULL);
64             return true;
65         }
66         return this->INHERITED::onQuery(evt);
67     }
68 
69     void onDraw(SkCanvas* canvas) override;
70 
onSendClickToChildren(SkScalar x,SkScalar y,unsigned modi)71     bool onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) override {
72         return false;
73     }
74 
onFindClickHandler(SkScalar cx,SkScalar cy,unsigned modi)75     Click* onFindClickHandler(SkScalar cx, SkScalar cy, unsigned modi) override {
76         const SkRect crect = SkRect::MakeXYWH(cx - 0.5f, cy - 0.5f, 1, 1);
77         SkPoint loc = this->start();
78         for (int i = 0; i < fCount; ++i) {
79             if (draw_this_name(fNames[i], fMatchStr)) {
80                 if (this->bounds(loc).intersects(crect)) {
81                     SkEvent evt("set-curr-index");
82                     evt.setFast32(i);
83                     this->sendEventToParents(evt);
84                     break;
85                 }
86                 this->next(&loc);
87             }
88         }
89         return NULL;
90     }
91 
92 private:
93     int fCount;
94     const SkViewFactory** fFactories;
95     SkString* fNames;
96     SkString fMatchStr;
97     SkPaint fNamePaint;
98     SkPaint::FontMetrics fNameMetrics;
99     SkScalar fNameW;
100     SkScalar fNameH;
101 
bounds(const SkPoint & loc) const102     SkRect bounds(const SkPoint& loc) const {
103         return SkRect::MakeXYWH(loc.x(), loc.y() + fNameMetrics.fAscent, fNameW, fNameH);
104     }
105 
start() const106     SkPoint start() const {
107         return SkPoint::Make(10, -fNameMetrics.fTop);
108     }
109 
next(SkPoint * loc) const110     void next(SkPoint* loc) const {
111         loc->fY += fNameH;
112         if (loc->fY > this->height() - fNameMetrics.fBottom) {
113             loc->fY = -fNameMetrics.fTop;
114             loc->fX += fNameW;
115         }
116     }
117 
118     typedef SkView INHERITED;
119 };
120 
create_overview(int count,const SkViewFactory * factories[])121 SkView* create_overview(int count, const SkViewFactory* factories[]) {
122     return SkNEW_ARGS(OverView, (count, factories));
123 }
124 
is_overview(SkView * view)125 bool is_overview(SkView* view) {
126     SkEvent isOverview(gIsOverview);
127     return view->doQuery(&isOverview);
128 }
129 
OverView(int count,const SkViewFactory * factories[])130 OverView::OverView(int count, const SkViewFactory* factories[]) {
131     fCount = count;
132     fFactories = factories;
133 
134     fNames = new SkString[count];
135     for (int i = 0; i < count; ++i) {
136         SkView* view = (*fFactories[i])();
137         if (view) {
138             (void)SampleCode::RequestTitle(view, &fNames[i]);
139             if (0 == fNames[i].find("GM:")) {
140                 fNames[i].remove(0, 3);
141             }
142         }
143     }
144 
145     fNamePaint.setAntiAlias(true);
146     fNamePaint.setTextSize(12);
147     fNameW = 160;
148     fNameH = fNamePaint.getFontMetrics(&fNameMetrics);
149 }
150 
~OverView()151 OverView::~OverView() {
152     delete[] fNames;
153 }
154 
onEvent(const SkEvent & evt)155 bool OverView::onEvent(const SkEvent& evt) {
156     return this->INHERITED::onEvent(evt);
157 }
158 
onDraw(SkCanvas * canvas)159 void OverView::onDraw(SkCanvas* canvas) {
160     SkPaint paint;
161     paint.setColor(0xFFF8F8F8);
162     canvas->drawPaint(paint);
163 
164     SkPoint loc = this->start();
165     for (int i = 0; i < fCount; ++i) {
166         if (draw_this_name(fNames[i], fMatchStr)) {
167             canvas->drawRect(this->bounds(loc), paint);
168             canvas->drawText(fNames[i].c_str(), fNames[i].size(), loc.x(), loc.y(), fNamePaint);
169             this->next(&loc);
170         }
171     }
172 }
173 
174