1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 6 июл. 2017 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <ui/tk/tk.h>
23 
24 namespace lsp
25 {
26     namespace tk
27     {
28         const w_class_t LSPLabel::metadata = { "LSPLabel", &LSPWidget::metadata };
29 
LSPLabel(LSPDisplay * dpy)30         LSPLabel::LSPLabel(LSPDisplay *dpy):
31             LSPWidget(dpy),
32             sFont(dpy, this),
33             sText(this)
34         {
35             fVAlign     = 0.5f;
36             fHAlign     = 0.5f;
37             nBorder     = 0;
38             nMinWidth   = -1;
39             nMinHeight  = -1;
40             pClass      = &metadata;
41 
42             sFont.set_size(12.0f);
43         }
44 
~LSPLabel()45         LSPLabel::~LSPLabel()
46         {
47         }
48 
init()49         status_t LSPLabel::init()
50         {
51             status_t result = LSPWidget::init();
52             if (result != STATUS_OK)
53                 return result;
54 
55             sFont.init();
56             init_color(C_LABEL_TEXT, sFont.color());
57 
58             sText.bind();
59 
60             return STATUS_OK;
61         }
62 
destroy()63         void LSPLabel::destroy()
64         {
65         }
66 
set_valign(float align)67         void LSPLabel::set_valign(float align)
68         {
69             fVAlign     = align;
70             query_draw();
71         }
72 
set_halign(float align)73         void LSPLabel::set_halign(float align)
74         {
75             fHAlign     = align;
76             query_draw();
77         }
78 
set_align(float halign,float valign)79         void LSPLabel::set_align(float halign, float valign)
80         {
81             fVAlign     = valign;
82             fHAlign     = halign;
83             query_draw();
84         }
85 
set_border(float border)86         void LSPLabel::set_border(float border)
87         {
88             nBorder     = border;
89             query_resize();
90         }
91 
draw(ISurface * s)92         void LSPLabel::draw(ISurface *s)
93         {
94             // Initialize palette
95             Color bg_color(sBgColor);
96             Color font_color(sFont.raw_color());
97 
98             font_color.scale_lightness(brightness());
99 
100             // Draw background
101             s->clear(bg_color);
102 
103             // Get text parameters
104             font_parameters_t fp;
105             text_parameters_t tp;
106             sFont.get_parameters(s, &fp);
107 
108             // Estimate number of lines
109             LSPString text;
110             sText.format(&text);
111 
112             ssize_t n_lines = 1 + text.count('\n');
113             ssize_t dy      = sSize.nHeight - fp.Height*n_lines - (nBorder << 1);
114             ssize_t y       = nBorder - fp.Descent + dy * fVAlign;
115 
116             // Estimate text size
117             ssize_t last = 0, curr = 0, tail = 0, len = text.length();
118 
119             while (curr < len)
120             {
121                 // Get next line indexes
122                 curr    = text.index_of(last, '\n');
123                 if (curr < 0)
124                 {
125                     curr        = len;
126                     tail        = len;
127                 }
128                 else
129                 {
130                     tail        = curr;
131                     if ((tail > last) && (text.at(tail-1) == '\r'))
132                         --tail;
133                 }
134 
135                 // Calculate text location
136                 sFont.get_text_parameters(s, &tp, &text, last, tail);
137                 ssize_t dx  = sSize.nWidth - tp.Width - (nBorder << 1);
138                 ssize_t x   = nBorder + dx * fHAlign - tp.XBearing;
139                 y          += fp.Height;
140 
141                 sFont.draw(s, x, y, font_color, &text, last, tail);
142                 last    = curr + 1;
143 
144 //                s->line(x - 3, y - 3, x + 3, y + 3, 1, red);
145 //                s->line(x + 3, y - 3, x - 3, y + 3, 1, red);
146 //
147 //                s->line(x - 3 + tp.XAdvance, y - 3, x + 3 + tp.XAdvance, y + 3, 1, yellow);
148 //                s->line(x + 3 + tp.XAdvance, y - 3, x - 3 + tp.XAdvance, y + 3, 1, yellow);
149 //                s->line(x - 3 + tp.XAdvance, y - 3, x + 3 + tp.XAdvance, y + 3, 1, yellow);
150 //                s->line(x + 3 + tp.XBearing, y - 3, x - 3 + tp.XBearing, y + 3, 1, yellow);
151             }
152         }
153 
set_min_width(ssize_t value)154         void LSPLabel::set_min_width(ssize_t value)
155         {
156             if (nMinWidth == value)
157                 return;
158             nMinWidth   = value;
159             query_resize();
160         }
161 
set_min_height(ssize_t value)162         void LSPLabel::set_min_height(ssize_t value)
163         {
164             if (nMinHeight == value)
165                 return;
166             nMinHeight  = value;
167             query_resize();
168         }
169 
size_request(size_request_t * r)170         void LSPLabel::size_request(size_request_t *r)
171         {
172             r->nMinWidth    = 0;
173             r->nMinHeight   = 0;
174             r->nMaxWidth    = -1;
175             r->nMaxHeight   = -1;
176 
177             LSPString text;
178             sText.format(&text);
179 
180             if (pDisplay == NULL)
181                 return;
182             ISurface *s = pDisplay->create_surface(1, 1);
183             if (s == NULL)
184                 return;
185 
186             text_parameters_t tp;
187             font_parameters_t fp;
188             sFont.get_parameters(s, &fp);
189             sFont.get_multiline_text_parameters(s, &tp, &text);
190             if (tp.Height < fp.Height)
191                 tp.Height   = fp.Height;
192 
193             r->nMinWidth    = tp.Width + (nBorder + 1) * 2;
194             r->nMinHeight   = tp.Height + (nBorder + 1) * 2;
195             if (fill())
196             {
197                 r->nMaxWidth    = -1;
198                 r->nMaxHeight   = -1;
199             }
200             else
201             {
202                 r->nMaxWidth    = r->nMinWidth;
203                 r->nMaxHeight   = r->nMinHeight;
204             }
205 
206             // Apply size constraints
207             if ((nMinWidth >= 0) && (r->nMinWidth < nMinWidth))
208                 r->nMinWidth    = nMinWidth;
209             if ((nMinHeight >= 0) && (r->nMinHeight < nMinHeight))
210                 r->nMinHeight   = nMinHeight;
211 
212             s->destroy();
213             delete s;
214         }
215 
query_safe_resize()216         void LSPLabel::query_safe_resize()
217         {
218             size_request_t sr;
219             size_request(&sr);
220             if (sr.nMinWidth < 0)
221                 sr.nMinWidth    = sSize.nWidth;
222             if (sr.nMinHeight < 0)
223                 sr.nMinHeight   = sSize.nHeight;
224 
225             if ((sr.nMinWidth > sSize.nWidth) || (sr.nMinHeight > sSize.nHeight))
226                 query_resize();
227             else if ((((sSize.nWidth - sr.nMinWidth) > 4) || ((sSize.nHeight - sr.nMinHeight) > 4)) && (!fill()))
228                 query_resize();
229             else
230                 query_draw();
231         }
232 
233     } /* namespace tk */
234 } /* namespace lsp */
235