1/*
2 * Copyright (C) 2020-2022 The opuntiaOS Project Authors.
3 * + Contributed by Nikita Melekhin <nimelehin@gmail.com>
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include <libfoundation/EventLoop.h>
10#include <libg/Color.h>
11#include <libui/Context.h>
12#include <libui/Label.h>
13
14namespace UI {
15
16Label::Label(View* superview, const LG::Rect& frame)
17 : View(superview, frame)
18{
19}
20
21Label::Label(View* superview, Window* window, const LG::Rect& frame)
22 : View(superview, window, frame)
23{
24}
25
26void Label::display(const LG::Rect& rect)
27{
28 LG::Context ctx = graphics_current_context();
29 ctx.add_clip(rect);
30
31 auto& f = font();
32 const size_t letter_spacing = f.glyph_spacing();
33
34 size_t label_width = bounds().width() - content_edge_insets().left() - content_edge_insets().right();
35 size_t txt_width = text_width();
36 size_t dots_width = font().glyph_width('.') * 3 + letter_spacing * 2;
37
38 bool need_to_stop_rendering_text = (txt_width > label_width);
39 size_t width_when_stop_rendering_text = content_edge_insets().left() + label_width - dots_width;
40
41 size_t content_width = text_width();
42 size_t content_height = text_height();
43 LG::Point<int> text_start { content_edge_insets().left(), std::max(content_edge_insets().top(), int(bounds().height() - content_height) / 2) };
44 if (alignment() == Text::Alignment::Center) {
45 int preffered_start = ((int)bounds().width() - (int)content_width) / 2;
46 text_start.set_x(std::max(content_edge_insets().left(), preffered_start));
47 } else if (alignment() == Text::Alignment::Right) {
48 int preffered_start = (int)bounds().width() - (int)content_width;
49 text_start.set_x(std::max(content_edge_insets().left(), preffered_start));
50 }
51
52 ctx.set_fill_color(text_color());
53 for (int i = 0; i < m_text.size(); i++) {
54 size_t glyph_width = f.glyph_width(m_text[i]) + letter_spacing;
55 if (need_to_stop_rendering_text && text_start.x() + glyph_width > width_when_stop_rendering_text) {
56 for (int j = 0; j < 3; j++) {
57 ctx.draw(text_start, f.glyph_bitmap('.'));
58 text_start.offset_by(f.glyph_width('.') + letter_spacing, 0);
59 }
60 return;
61 }
62 ctx.draw(text_start, f.glyph_bitmap(m_text[i]));
63 text_start.offset_by(glyph_width, 0);
64 }
65}
66
67void Label::mouse_entered(const LG::Point<int>& location)
68{
69 set_hovered(true);
70}
71
72void Label::mouse_exited()
73{
74 set_hovered(false);
75}
76
77void Label::recalc_bounds()
78{
79 size_t new_width = text_width() + content_edge_insets().left() + content_edge_insets().right();
80 size_t new_height = text_height() + content_edge_insets().top() + content_edge_insets().bottom();
81 set_width(new_width);
82 set_height(new_height);
83}
84
85size_t Label::text_width() const
86{
87 if (!m_text.size()) {
88 return 0;
89 }
90
91 size_t width = 0;
92 auto& f = font();
93 const size_t letter_spacing = f.glyph_spacing();
94
95 for (int i = 0; i < m_text.size(); i++) {
96 width += f.glyph_width(m_text[i]) + letter_spacing;
97 }
98 return width - letter_spacing;
99}
100
101size_t Label::text_height() const
102{
103 return font().glyph_height();
104}
105
106} // namespace UI