1 /*
2  *
3  * Copyright 2019, The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #ifndef LIBTEEUI_LABEL_H_
19 #define LIBTEEUI_LABEL_H_
20 
21 #include "utf8range.h"
22 #include "utils.h"
23 
24 // #define DRAW_DEBUG_MARKERS
25 
26 namespace teeui {
27 
28 enum class Alignment : int8_t { LEFT, CENTER, RIGHT, TOP, BOTTOM };
29 
30 class FontBuffer {
31     const uint8_t* data_;
32     size_t size_;
33 
34   public:
FontBuffer()35     constexpr FontBuffer() : data_(nullptr), size_(0) {}
FontBuffer(const uint8_t * data,size_t size)36     constexpr FontBuffer(const uint8_t* data, size_t size) noexcept : data_(data), size_(size) {}
37     template <size_t size>
FontBuffer(const uint8_t (& data)[size])38     explicit constexpr FontBuffer(const uint8_t (&data)[size]) noexcept
39         : data_(&data[0]), size_(size) {}
40     constexpr FontBuffer(const FontBuffer&) noexcept = default;
41     constexpr FontBuffer(FontBuffer&&) noexcept = default;
42     FontBuffer& operator=(FontBuffer&&) noexcept = default;
43     FontBuffer& operator=(const FontBuffer&) noexcept = default;
44 
45     constexpr operator bool() const { return data_ != nullptr; }
46 
data()47     const uint8_t* data() const { return data_; }
size()48     size_t size() const { return size_; }
49 };
50 
51 class LabelImpl {
52     using text_t = UTF8Range<const char*>;
53 
54   public:
55     struct LineInfo {
56         struct info_t {
57             Point<pxs> lineStart;
58             text_t lineText;
59         };
60         size_t size_;
61         info_t* info_;
beginLineInfo62         info_t* begin() { return &info_[0]; }
endLineInfo63         info_t* end() { return &info_[size_]; }
beginLineInfo64         const info_t* begin() const { return &info_[0]; }
endLineInfo65         const info_t* end() const { return &info_[size_]; }
66     };
67 
LabelImpl()68     LabelImpl()
69         : fontSize_(10_px), lineHeight_(12_px), text_{}, horizontalTextAlignment_(Alignment::LEFT),
70           verticalTextAlignment_(Alignment::TOP), textColor_(0), font_{}, textId_(0) {}
LabelImpl(pxs fontSize,pxs lineHeight,text_t text,Alignment horizontal,Alignment verticalJustified,Color textColor,FontBuffer font,uint64_t textId)71     LabelImpl(pxs fontSize, pxs lineHeight, text_t text, Alignment horizontal,
72               Alignment verticalJustified, Color textColor, FontBuffer font, uint64_t textId)
73         : fontSize_(fontSize), lineHeight_(lineHeight), text_(text),
74           horizontalTextAlignment_(horizontal), verticalTextAlignment_(verticalJustified),
75           textColor_(textColor), font_(font), textId_(textId) {}
76 
fontSize()77     pxs fontSize() const { return fontSize_; }
78 
setText(text_t text)79     void setText(text_t text) { text_ = text; }
setTextColor(Color color)80     void setTextColor(Color color) { textColor_ = color; }
81 
text()82     text_t text() const { return text_; }
textId()83     uint64_t textId() const { return textId_; }
84 
85     Error draw(const PixelDrawer& drawPixel, const Box<pxs>& bounds, LineInfo* lineInfo);
setCB(CallbackEvent cbEvent)86     void setCB(CallbackEvent cbEvent) { cbEvent_ = std::move(cbEvent); }
getCB()87     optional<CallbackEvent> getCB() { return cbEvent_; }
88     Error hit(const Event& event, const Box<pxs>& bounds);
89 
90   private:
91     pxs fontSize_;
92     pxs lineHeight_;
93     text_t text_;
94     Alignment horizontalTextAlignment_;
95     Alignment verticalTextAlignment_;
96     Color textColor_;
97     FontBuffer font_;
98     uint64_t textId_;
99     optional<CallbackEvent> cbEvent_;
100 };
101 
102 /**
103  * Label is a LayoutElement and should be used as second argument in the BEGIN_ELEMENT() macro.
104  * The template argument Derived is the new class derived from Label, that is created by the
105  * BEGIN_ELEMENT() macro.
106  */
107 template <typename Derived> class Label : public LayoutElement<Derived>, public LabelImpl {
108   public:
109     static const constexpr Alignment label_horizontal_text_alignment = Alignment::LEFT;
110     static const constexpr Alignment label_vertical_text_alignment = Alignment::TOP;
111     static const constexpr Color label_text_color = 0xff000000;
112     static const constexpr int label_font = 0;
113     static const constexpr uint64_t text_id = 0;
114 
115     Label() = default;
116     template <typename Context>
Label(const Context & context)117     Label(const Context& context)
118         : LayoutElement<Derived>(context),
119           LabelImpl(
120               context = Derived::label_font_size, context = Derived::label_line_height,
121               {&Derived::label_text[0], &Derived::label_text[sizeof(Derived::label_text) - 1]},
122               Derived::label_horizontal_text_alignment, Derived::label_vertical_text_alignment,
123               context = Derived::label_text_color, getFont(Derived::label_font), Derived::text_id) {
124     }
125 
draw(const PixelDrawer & drawPixel)126     Error draw(const PixelDrawer& drawPixel) {
127         LabelImpl::LineInfo::info_t lines[Derived::label_number_of_lines];
128         LabelImpl::LineInfo lineInfo = {Derived::label_number_of_lines, lines};
129         return LabelImpl::draw(drawPixel, this->bounds_, &lineInfo);
130     }
131 
hit(const Event & event)132     Error hit(const Event& event) { return LabelImpl::hit(event, this->bounds_); }
133 };
134 
135 }  //  namespace teeui
136 
137 #define FontSize(fs) static const constexpr auto label_font_size = fs
138 
139 #define DefaultText(text) static const constexpr char label_text[] = text
140 
141 #define LineHeight(height) static const constexpr auto label_line_height = height
142 
143 #define NumberOfLines(lines) static const constexpr auto label_number_of_lines = lines
144 
145 #define HeightFromLines (label_line_height * pxs(label_number_of_lines))
146 
147 #define HorizontalTextAlignment(horizontalAligment)                                                \
148     static const constexpr Alignment label_horizontal_text_alignment = horizontalAligment;
149 
150 #define RightJustified HorizontalTextAlignment(Alignment::RIGHT)
151 
152 #define VerticalTextAlignment(verticalAligment)                                                    \
153     static const constexpr Alignment label_vertical_text_alignment = verticalAligment;
154 
155 #define VerticallyCentered VerticalTextAlignment(Alignment::CENTER)
156 
157 #define TextColor(color) static const constexpr auto label_text_color = color
158 
159 #define FONT(name) TEEUI_FONT_##name()
160 
161 #define DECLARE_FONT_BUFFER(name, buffer, ...)                                                     \
162     struct TEEUI_FONT_##name {};                                                                   \
163     inline FontBuffer getFont(TEEUI_FONT_##name) { return FontBuffer(buffer, ##__VA_ARGS__); }
164 
165 #define Font(fontbuffer) static const constexpr auto label_font = fontbuffer
166 
167 #define TextID(tid) static const constexpr uint64_t text_id = tid
168 
169 #endif  // LIBTEEUI_LABEL_H_
170