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: 19 июл. 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 LSPText::metadata = { "LSPText", &LSPGraphItem::metadata }; 29 LSPText(LSPDisplay * dpy)30 LSPText::LSPText(LSPDisplay *dpy): 31 LSPGraphItem(dpy), 32 sText(this), 33 sFont(dpy, this) 34 { 35 nCoords = 0; 36 vCoords = NULL; 37 fHAlign = 0.0; 38 fVAlign = 0.0; 39 nCenter = 0; 40 41 pClass = &metadata; 42 } 43 ~LSPText()44 LSPText::~LSPText() 45 { 46 do_destroy(); 47 } 48 destroy()49 void LSPText::destroy() 50 { 51 LSPGraphItem::destroy(); 52 do_destroy(); 53 } 54 do_destroy()55 void LSPText::do_destroy() 56 { 57 if (vCoords != NULL) 58 { 59 free(vCoords); 60 vCoords = NULL; 61 } 62 nCoords = 0; 63 } 64 init()65 status_t LSPText::init() 66 { 67 sText.bind(); 68 69 status_t result = LSPGraphItem::init(); 70 if (result != STATUS_OK) 71 return result; 72 73 init_color(C_GRAPH_TEXT, sFont.color()); 74 vCoords = reinterpret_cast<coord_t *>(malloc(2 * sizeof(coord_t))); 75 if (vCoords == NULL) 76 return STATUS_NO_MEM; 77 nCoords = 2; 78 for (size_t i=0; i<nCoords; ++i) 79 { 80 vCoords[i].nBasis = i; 81 vCoords[i].fCoord = 0.0f; 82 } 83 84 sFont.init(); 85 sFont.set_size(10.0f); 86 87 return STATUS_OK; 88 } 89 set_axes(size_t axes)90 status_t LSPText::set_axes(size_t axes) 91 { 92 if (nCoords == axes) 93 return STATUS_OK; 94 if (axes == 0) 95 { 96 if (vCoords != NULL) 97 { 98 free(vCoords); 99 vCoords = NULL; 100 } 101 nCoords = 0; 102 query_draw(); 103 return STATUS_OK; 104 } 105 106 coord_t *ptr = (vCoords != NULL) ? 107 reinterpret_cast<coord_t *>(realloc(vCoords, sizeof(coord_t) * axes)) : 108 reinterpret_cast<coord_t *>(malloc(sizeof(coord_t) * axes)); 109 if (ptr == NULL) 110 return STATUS_NO_MEM; 111 for (size_t i=nCoords; i<axes; ++i) 112 { 113 ptr[i].nBasis = i; 114 ptr[i].fCoord = 0.0f; 115 } 116 117 vCoords = ptr; 118 nCoords = axes; 119 return STATUS_OK; 120 } 121 set_coord(size_t axis,float value)122 status_t LSPText::set_coord(size_t axis, float value) 123 { 124 if ((axis < 0) || (axis >= nCoords)) 125 return STATUS_OVERFLOW; 126 if (vCoords[axis].fCoord == value) 127 return STATUS_OK; 128 vCoords[axis].fCoord = value; 129 query_draw(); 130 131 return STATUS_OK; 132 } 133 set_basis(size_t axis,size_t value)134 status_t LSPText::set_basis(size_t axis, size_t value) 135 { 136 if ((axis < 0) || (axis >= nCoords)) 137 return STATUS_OVERFLOW; 138 if (vCoords[axis].nBasis == value) 139 return STATUS_OK; 140 vCoords[axis].nBasis = value; 141 query_draw(); 142 143 return STATUS_OK; 144 } 145 get_coord(size_t axis) const146 float LSPText::get_coord(size_t axis) const 147 { 148 return ((axis < 0) || (axis >= nCoords)) ? vCoords[axis].fCoord : 0.0f; 149 } 150 get_basis(size_t axis) const151 size_t LSPText::get_basis(size_t axis) const 152 { 153 return ((axis < 0) || (axis >= nCoords)) ? vCoords[axis].nBasis : 0; 154 } 155 set_halign(float value)156 void LSPText::set_halign(float value) 157 { 158 if (fHAlign == value) 159 return; 160 fHAlign = value; 161 query_draw(); 162 } 163 set_valign(float value)164 void LSPText::set_valign(float value) 165 { 166 if (fVAlign == value) 167 return; 168 fVAlign = value; 169 query_draw(); 170 } 171 set_center(size_t value)172 void LSPText::set_center(size_t value) 173 { 174 if (nCenter == value) 175 return; 176 nCenter = value; 177 query_draw(); 178 } 179 render(ISurface * s,bool force)180 void LSPText::render(ISurface *s, bool force) 181 { 182 if (vCoords == NULL) 183 return; 184 185 LSPString text; 186 sText.format(&text); 187 if (text.is_empty()) 188 return; 189 190 LSPGraph *cv = graph(); 191 if (cv == NULL) 192 return; 193 194 // Get palette 195 Color font_color(sFont.raw_color()); 196 font_color.scale_lightness(brightness()); 197 198 // Get center 199 float x = 0.0f, y = 0.0f; 200 cv->center(nCenter, &x, &y); 201 202 // Apply all axis 203 for (size_t i=0; i<nCoords; ++i) 204 { 205 coord_t *coord = &vCoords[i]; 206 // Get axis 207 LSPAxis *axis = cv->axis(coord->nBasis); 208 if (axis == NULL) 209 return; 210 // Apply changes 211 if (!axis->apply(&x, &y, &coord->fCoord, 1)) 212 return; 213 } 214 215 // Now we are ready to output text 216 font_parameters_t fp; 217 text_parameters_t tp; 218 219 sFont.get_parameters(s, &fp); 220 sFont.get_multiline_text_parameters(s, &tp, &text); 221 222 // Center point 223 ssize_t n_lines = 1 + text.count('\n'); 224 ssize_t ty = y - fp.Height * n_lines * (fVAlign + 1.0f)*0.5f - fp.Descent; 225 ssize_t tw = tp.Width; 226 227 // Estimate text size 228 ssize_t last = 0, curr = 0, tail = 0, len = text.length(); 229 230 while (curr < len) 231 { 232 // Get next line indexes 233 curr = text.index_of(last, '\n'); 234 if (curr < 0) 235 { 236 curr = len; 237 tail = len; 238 } 239 else 240 { 241 tail = curr; 242 if ((tail > last) && (text.at(tail-1) == '\r')) 243 --tail; 244 } 245 246 // Calculate text location 247 sFont.get_text_parameters(s, &tp, &text, last, tail); 248 ssize_t tx = x + (tw - tp.Width*0.5f)*(fHAlign - 1.0f) + fHAlign*2.0f; 249 ty += fp.Height; 250 sFont.draw(s, tx, ty, font_color, &text, last, tail); 251 252 last = curr + 1; 253 } 254 } 255 256 } /* namespace tk */ 257 } /* namespace lsp */ 258