OverView.cpp revision 385fe4d4b62d7d1dd76116dd570df3290a2f487b
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
13static const char gIsOverview[] = "is-overview";
14
15static int to_lower(int c) {
16    if ('A' <= c && c <= 'Z') {
17        c = c - 'A' + 'a';
18    }
19    return c;
20}
21
22static 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
30static 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
38static 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
45class OverView : public SkView {
46public:
47    OverView(int count, const SkViewFactory* factories[]);
48    virtual ~OverView();
49
50protected:
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            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
71    bool onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) override {
72        return false;
73    }
74
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
92private:
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
102    SkRect bounds(const SkPoint& loc) const {
103        return SkRect::MakeXYWH(loc.x(), loc.y() + fNameMetrics.fAscent, fNameW, fNameH);
104    }
105
106    SkPoint start() const {
107        return SkPoint::Make(10, -fNameMetrics.fTop);
108    }
109
110    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
121SkView* create_overview(int count, const SkViewFactory* factories[]) {
122    return new OverView(count, factories);
123}
124
125bool is_overview(SkView* view) {
126    SkEvent isOverview(gIsOverview);
127    return view->doQuery(&isOverview);
128}
129
130OverView::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
151OverView::~OverView() {
152    delete[] fNames;
153}
154
155bool OverView::onEvent(const SkEvent& evt) {
156    return this->INHERITED::onEvent(evt);
157}
158
159void 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