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: 29 апр. 2018 г. 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 29 const w_class_t LSPComboGroup::metadata = { "LSPComboGroup", &LSPWidgetContainer::metadata }; 30 31 //--------------------------------------------------------------------- LSPComboList(LSPDisplay * dpy,LSPComboGroup * widget)32 LSPComboGroup::LSPComboList::LSPComboList(LSPDisplay *dpy, LSPComboGroup *widget): LSPListBox(dpy) 33 { 34 pWidget = widget; 35 } 36 ~LSPComboList()37 LSPComboGroup::LSPComboList::~LSPComboList() 38 { 39 } 40 on_selection_change()41 void LSPComboGroup::LSPComboList::on_selection_change() 42 { 43 LSPListBox::on_selection_change(); 44 pWidget->on_selection_change(); 45 } 46 on_item_change(ssize_t index,LSPItem * item)47 void LSPComboGroup::LSPComboList::on_item_change(ssize_t index, LSPItem *item) 48 { 49 LSPListBox::on_item_change(index, item); 50 pWidget->on_item_change(index, item); 51 } 52 on_item_add(size_t index)53 void LSPComboGroup::LSPComboList::on_item_add(size_t index) 54 { 55 LSPListBox::on_item_add(index); 56 pWidget->on_item_add(index); 57 } 58 on_item_remove(size_t index)59 void LSPComboGroup::LSPComboList::on_item_remove(size_t index) 60 { 61 LSPListBox::on_item_remove(index); 62 pWidget->on_item_remove(index); 63 } 64 on_item_swap(size_t idx1,size_t idx2)65 void LSPComboGroup::LSPComboList::on_item_swap(size_t idx1, size_t idx2) 66 { 67 LSPListBox::on_item_swap(idx1, idx2); 68 pWidget->on_item_swap(idx1, idx2); 69 } 70 on_item_clear()71 void LSPComboGroup::LSPComboList::on_item_clear() 72 { 73 LSPListBox::on_item_clear(); 74 pWidget->on_item_clear(); 75 } 76 77 //--------------------------------------------------------------------- LSPComboPopup(LSPDisplay * dpy,LSPComboGroup * widget,ssize_t screen)78 LSPComboGroup::LSPComboPopup::LSPComboPopup(LSPDisplay *dpy, LSPComboGroup *widget, ssize_t screen): 79 LSPWindow(dpy, NULL, screen) 80 { 81 pWidget = widget; 82 } 83 ~LSPComboPopup()84 LSPComboGroup::LSPComboPopup::~LSPComboPopup() 85 { 86 } 87 handle_event(const ws_event_t * e)88 status_t LSPComboGroup::LSPComboPopup::handle_event(const ws_event_t *e) 89 { 90 switch (e->nType) 91 { 92 case UIE_KEY_DOWN: 93 pWidget->on_grab_key_down(e); 94 break; 95 } 96 return LSPWindow::handle_event(e); 97 } 98 99 //--------------------------------------------------------------------- LSPComboGroup(LSPDisplay * dpy)100 LSPComboGroup::LSPComboGroup(LSPDisplay *dpy): 101 LSPWidgetContainer(dpy), 102 sColor(this), 103 sListBox(dpy, this), 104 sFont(this) 105 { 106 nRadius = 10; 107 nBorder = 0; 108 nCBFlags = 0; 109 nMFlags = 0; 110 pPopup = NULL; 111 bEmbed = false; 112 113 sGroupHdr.nLeft = 0; 114 sGroupHdr.nTop = 0; 115 sGroupHdr.nWidth = 0; 116 sGroupHdr.nHeight = 0; 117 118 pClass = &metadata; 119 } 120 ~LSPComboGroup()121 LSPComboGroup::~LSPComboGroup() 122 { 123 do_destroy(); 124 } 125 init()126 status_t LSPComboGroup::init() 127 { 128 status_t result = LSPWidgetContainer::init(); 129 if (result != STATUS_OK) 130 return result; 131 132 // Init list box 133 result = sListBox.init(); 134 if (result != STATUS_OK) 135 return result; 136 137 sFont.init(); 138 sFont.set_size(12.0f); 139 init_color(C_LABEL_TEXT, &sColor); 140 init_color(C_BACKGROUND, sFont.color()); 141 142 // Bind slots 143 ui_handler_id_t id = 0; 144 id = sSlots.add(LSPSLOT_CHANGE, slot_on_change, self()); 145 if (id >= 0) id = sSlots.add(LSPSLOT_SUBMIT, slot_on_submit, self()); 146 if (id >= 0) id = sListBox.slots()->bind(LSPSLOT_CHANGE, slot_on_list_change, self()); 147 if (id >= 0) id = sListBox.slots()->bind(LSPSLOT_SUBMIT, slot_on_list_submit, self()); 148 149 return (id >= 0) ? STATUS_OK : -id; 150 } 151 destroy()152 void LSPComboGroup::destroy() 153 { 154 do_destroy(); 155 LSPWidgetContainer::destroy(); 156 } 157 current_widget()158 LSPWidget *LSPComboGroup::current_widget() 159 { 160 ssize_t idx = sListBox.selection()->value(); 161 if (idx >= ssize_t(vWidgets.size())) 162 idx = vWidgets.size() - 1; 163 LSPWidget *w = vWidgets.get(idx); 164 return ((w == NULL) || (w->invisible())) ? NULL : w; 165 } 166 find_widget(ssize_t x,ssize_t y)167 LSPWidget *LSPComboGroup::find_widget(ssize_t x, ssize_t y) 168 { 169 LSPWidget *curr = current_widget(); 170 return ((curr != NULL) && (curr->inside(x, y))) ? curr : NULL; 171 } 172 query_dimensions(dimensions_t * d)173 void LSPComboGroup::query_dimensions(dimensions_t *d) 174 { 175 size_t bw = (bEmbed) ? 1 : ::round(nRadius * M_SQRT2 * 0.5) + 1; 176 size_t dd = bw + nBorder + 1; 177 d->nGapLeft = dd; 178 d->nGapRight = dd; 179 d->nGapTop = dd; 180 d->nGapBottom = dd; 181 d->nMinWidth = nBorder*2; 182 d->nMinHeight = nBorder*2; 183 184 LSPString text; 185 const LSPLocalString *lctext = this->text(); 186 if (lctext != NULL) 187 lctext->format(&text, this); 188 if (text.length() > 0) 189 { 190 // Create temporary surface 191 ISurface *s = (pDisplay != NULL) ? pDisplay->create_surface(1, 1) : NULL; 192 if (s == NULL) 193 return; 194 195 font_parameters_t fp; 196 text_parameters_t tp; 197 198 sFont.get_parameters(s, &fp); 199 sFont.get_text_parameters(s, &tp, &text); 200 201 d->nMinWidth += tp.Width + nRadius * 3; 202 d->nMinHeight += fp.Height + nRadius * 2; 203 d->nGapTop += fp.Height; 204 205 // Destroy surface 206 s->destroy(); 207 delete s; 208 } 209 } 210 do_destroy()211 void LSPComboGroup::do_destroy() 212 { 213 size_t count = vWidgets.size(); 214 for (size_t i=0; i<count; ++i) 215 { 216 LSPWidget *w = vWidgets.get(i); 217 if (w != NULL) 218 unlink_widget(w); 219 } 220 vWidgets.clear(); 221 } 222 check_mouse_over(ssize_t x,ssize_t y)223 bool LSPComboGroup::check_mouse_over(ssize_t x, ssize_t y) 224 { 225 x -= sGroupHdr.nLeft; 226 y -= sGroupHdr.nTop; 227 228 return (x >= 0) && (y >= 0) && (x < sGroupHdr.nWidth) && (y < sGroupHdr.nHeight); 229 } 230 set_radius(size_t value)231 void LSPComboGroup::set_radius(size_t value) 232 { 233 if (nRadius == value) 234 return; 235 nRadius = value; 236 query_resize(); 237 } 238 set_border(size_t value)239 void LSPComboGroup::set_border(size_t value) 240 { 241 if (nBorder == value) 242 return; 243 nBorder = value; 244 query_resize(); 245 } 246 render(ISurface * s,bool force)247 void LSPComboGroup::render(ISurface *s, bool force) 248 { 249 if (nFlags & REDRAW_SURFACE) 250 force = true; 251 252 // Prepare palette 253 Color bg_color(sBgColor); 254 Color color(sColor); 255 color.scale_lightness(brightness()); 256 257 // lsp_trace("Rendering this=%p, force=%d", this, int(force)); 258 LSPWidget *current = current_widget(); 259 260 // Draw child 261 if (current != NULL) 262 { 263 if ((force) || (current->redraw_pending())) 264 { 265 current->render(s, force); 266 current->commit_redraw(); 267 } 268 } 269 270 if (force) 271 { 272 // Get resource 273 ssize_t cx = sSize.nLeft + nBorder + 1; 274 ssize_t cy = sSize.nTop + nBorder + 1; 275 ssize_t sx = sSize.nWidth - (nBorder << 1) - 1; 276 ssize_t sy = sSize.nHeight - (nBorder << 1) - 1; 277 // size_t bw = round(nRadius * M_SQRT2 * 0.5f) + 1; 278 279 // Draw background 280 if (current == NULL) 281 s->fill_rect(sSize.nLeft, sSize.nTop, sSize.nWidth, sSize.nHeight, bg_color); 282 else 283 { 284 realize_t r; 285 current->get_dimensions(&r); 286 287 if ((bEmbed) && (nRadius > 1)) 288 s->fill_round_frame( 289 sSize.nLeft, sSize.nTop, sSize.nWidth, sSize.nHeight, 290 r.nLeft, r.nTop, r.nWidth, r.nHeight, 291 nRadius-1, SURFMASK_B_CORNER, 292 bg_color 293 ); 294 else 295 s->fill_frame( 296 sSize.nLeft, sSize.nTop, sSize.nWidth, sSize.nHeight, 297 r.nLeft, r.nTop, r.nWidth, r.nHeight, 298 bg_color 299 ); 300 } 301 302 // Draw frame 303 bool aa = s->set_antialiasing(true); 304 s->wire_round_rect(cx, cy, sx-1, sy-1, nRadius, 0x0e, 2.0f, color); 305 306 ssize_t bwidth = 12; 307 sGroupHdr.nLeft = cx; 308 sGroupHdr.nTop = cy; 309 sGroupHdr.nWidth = nRadius; 310 sGroupHdr.nHeight = nRadius; 311 312 // Draw text frame 313 LSPString text; 314 const LSPLocalString *lctext = this->text(); 315 if (lctext != NULL) 316 lctext->format(&text, this); 317 if (text.length() > 0) 318 { 319 // Draw text border 320 font_parameters_t fp; 321 text_parameters_t tp; 322 sFont.get_parameters(s, &fp); 323 sFont.get_text_parameters(s, &tp, &text); 324 325 sGroupHdr.nWidth = 4 + nRadius + tp.Width + bwidth; 326 sGroupHdr.nHeight = fp.Height + 4; 327 328 s->fill_round_rect(cx - 1, cy-1, sGroupHdr.nWidth, sGroupHdr.nHeight, nRadius, 0x04, color); 329 330 // Show text 331 Color font(sFont.raw_color()); 332 font.scale_lightness(brightness()); 333 334 sFont.draw(s, cx + bwidth + 4 , cy + fp.Ascent + nBorder, font, &text); 335 336 // Draw buttons 337 ssize_t half = sGroupHdr.nTop + (fp.Height * 0.5f); 338 339 s->fill_triangle( 340 cx + 2, half - 2, 341 cx + bwidth - 2, half - 2, 342 cx + bwidth*0.5f, half - 6, 343 font); 344 345 s->fill_triangle( 346 cx + 2, half + 1, 347 cx + bwidth - 2, half + 1, 348 cx + bwidth*0.5f, half + 5, 349 font); 350 351 s->set_antialiasing(false); 352 s->line(cx + bwidth + 2, cy + 1, cx + bwidth + 2, cy + fp.Height + 1, 1, font); 353 } 354 355 s->set_antialiasing(aa); 356 } 357 } 358 add(LSPWidget * widget)359 status_t LSPComboGroup::add(LSPWidget *widget) 360 { 361 widget->set_parent(this); 362 vWidgets.add(widget); 363 query_resize(); 364 return STATUS_OK; 365 } 366 remove(LSPWidget * widget)367 status_t LSPComboGroup::remove(LSPWidget *widget) 368 { 369 if (vWidgets.remove(widget, false)) 370 return STATUS_NOT_FOUND; 371 372 unlink_widget(widget); 373 return STATUS_OK; 374 } 375 size_request(size_request_t * r)376 void LSPComboGroup::size_request(size_request_t *r) 377 { 378 LSPWidget *w = current_widget(); 379 if (w != NULL) 380 w->size_request(r); 381 382 if (r->nMinWidth < 0) 383 r->nMinWidth = 0; 384 if (r->nMinHeight < 0) 385 r->nMinHeight = 0; 386 387 if (w != NULL) 388 { 389 r->nMinWidth += w->padding()->horizontal(); 390 r->nMinHeight += w->padding()->vertical(); 391 } 392 393 dimensions_t d; 394 query_dimensions(&d); 395 396 if (r->nMinWidth >= 0) 397 { 398 size_t n = r->nMinWidth + d.nGapLeft + d.nGapRight; 399 if (n < d.nMinWidth) 400 r->nMinWidth = d.nMinWidth; 401 else 402 r->nMinWidth = n; 403 } 404 if (r->nMinHeight >= 0) 405 { 406 size_t n = r->nMinHeight + d.nGapTop + d.nGapBottom; 407 if (n < d.nMinHeight) 408 r->nMinHeight = d.nMinHeight; 409 else 410 r->nMinHeight = n; 411 } 412 413 // Align to 8-pixel grid 414 // r->nMinWidth = ((r->nMinWidth + 7) >> 3) << 3; 415 // r->nMinHeight = ((r->nMinHeight + 7) >> 3) << 3; 416 417 if ((r->nMaxWidth >= 0) && (r->nMaxWidth < r->nMinWidth)) 418 r->nMaxWidth = r->nMinWidth; 419 if ((r->nMaxHeight >= 0) && (r->nMaxHeight < r->nMinHeight)) 420 r->nMaxHeight = r->nMinHeight; 421 } 422 realize(const realize_t * r)423 void LSPComboGroup::realize(const realize_t *r) 424 { 425 LSPWidgetContainer::realize(r); 426 LSPWidget *w = current_widget(); 427 if (w == NULL) 428 return; 429 430 dimensions_t d; 431 query_dimensions(&d); 432 433 size_request_t sr; 434 w->size_request(&sr); 435 436 realize_t rc; 437 rc.nLeft = r->nLeft + d.nGapLeft + w->padding()->left(); 438 rc.nTop = r->nTop + d.nGapTop + w->padding()->top(); 439 rc.nWidth = r->nWidth - d.nGapLeft - d.nGapRight - w->padding()->horizontal(); 440 rc.nHeight = r->nHeight - d.nGapTop - d.nGapBottom - w->padding()->vertical(); 441 442 if ((sr.nMaxWidth > 0) && (sr.nMaxWidth < rc.nWidth)) 443 { 444 rc.nLeft += (rc.nWidth - sr.nMaxWidth) >> 1; 445 rc.nWidth = sr.nMaxWidth; 446 } 447 448 if ((sr.nMaxHeight > 0) && (sr.nMaxHeight < rc.nHeight)) 449 { 450 rc.nTop += (rc.nHeight - sr.nMaxHeight) >> 1; 451 rc.nHeight = sr.nMaxHeight; 452 } 453 454 w->realize(&rc); 455 } 456 on_mouse_down(const ws_event_t * e)457 status_t LSPComboGroup::on_mouse_down(const ws_event_t *e) 458 { 459 if (!check_mouse_over(e->nLeft, e->nTop)) 460 { 461 nCBFlags |= F_MOUSE_OUT; 462 return STATUS_OK; 463 } 464 465 take_focus(); 466 nMFlags |= (1 << e->nCode); 467 return STATUS_OK; 468 } 469 on_mouse_up(const ws_event_t * e)470 status_t LSPComboGroup::on_mouse_up(const ws_event_t *e) 471 { 472 size_t flags = nMFlags; 473 nMFlags &= ~(1 << e->nCode); 474 475 if (nCBFlags & F_MOUSE_OUT) 476 { 477 if (!nMFlags) 478 nCBFlags &= ~F_MOUSE_OUT; 479 return STATUS_OK; 480 } 481 482 if ((e->nCode == MCB_LEFT) && (flags == size_t(1 << e->nCode))) 483 { 484 if (inside(e->nLeft, e->nTop)) 485 toggle(); 486 } 487 488 return STATUS_OK; 489 } 490 on_mouse_scroll(const ws_event_t * e)491 status_t LSPComboGroup::on_mouse_scroll(const ws_event_t *e) 492 { 493 if (!check_mouse_over(e->nLeft, e->nTop)) 494 return STATUS_OK; 495 496 ssize_t selection = sListBox.selection()->value(); 497 ssize_t old = selection; 498 ssize_t last = sListBox.items()->size() - 1; 499 500 if (e->nCode == MCD_UP) 501 { 502 if (selection > 0) 503 selection --; 504 else if (selection == 0) 505 { 506 if (!(nCBFlags & F_CIRCULAR)) 507 return STATUS_OK; 508 selection = last; 509 } 510 else 511 selection = sListBox.items()->size() - 1; 512 } 513 else if (e->nCode == MCD_DOWN) 514 { 515 if (selection >= 0) 516 { 517 if (selection < last) 518 selection ++; 519 else if (!(nCBFlags & F_CIRCULAR)) 520 return STATUS_OK; 521 else 522 selection = 0; 523 } 524 else 525 selection = 0; 526 } 527 else 528 return STATUS_OK; 529 530 sListBox.selection()->set_value(selection); 531 if (sListBox.selection()->value() == old) 532 return STATUS_OK; 533 534 sSlots.execute(LSPSLOT_CHANGE, this); 535 return sSlots.execute(LSPSLOT_SUBMIT, this); 536 } 537 on_change()538 status_t LSPComboGroup::on_change() 539 { 540 return STATUS_OK; 541 } 542 on_submit()543 status_t LSPComboGroup::on_submit() 544 { 545 lsp_trace("on_submit"); 546 close(); 547 return STATUS_OK; 548 } 549 text() const550 const LSPLocalString *LSPComboGroup::text() const 551 { 552 LSPComboList *lb = const_cast<LSPComboList *>(&sListBox); 553 ssize_t idx = lb->selection()->value(); 554 LSPItem *itm = lb->items()->get(idx); 555 return (itm != NULL) ? itm->text() : NULL; 556 } 557 selected() const558 ssize_t LSPComboGroup::selected() const 559 { 560 LSPComboList *lb = const_cast<LSPComboList *>(&sListBox); 561 return lb->selection()->value(); 562 } 563 set_selected(ssize_t value)564 status_t LSPComboGroup::set_selected(ssize_t value) 565 { 566 return sListBox.selection()->set_value(value); 567 } 568 set_opened(bool open)569 status_t LSPComboGroup::set_opened(bool open) 570 { 571 if (open == bool(nCBFlags & F_OPENED)) 572 return STATUS_OK; 573 574 // Check if we need to close combo box 575 if (!open) 576 { 577 if (pPopup != NULL) 578 pPopup->hide(); 579 sListBox.hide(); 580 581 nCBFlags &= ~F_OPENED; 582 return STATUS_OK; 583 } 584 585 LSPWindow *parent = widget_cast<LSPWindow>(toplevel()); 586 587 // Now we need to open combo box 588 // Create popup window 589 if (pPopup == NULL) 590 { 591 if (parent != NULL) 592 pPopup = new LSPComboPopup(pDisplay, this, parent->screen()); 593 else 594 pPopup = new LSPComboPopup(pDisplay, this); 595 if (pPopup == NULL) 596 return STATUS_NO_MEM; 597 598 status_t result = pPopup->init(); 599 if (result != STATUS_OK) 600 { 601 pPopup->destroy(); 602 delete pPopup; 603 pPopup = NULL; 604 return result; 605 } 606 607 pPopup->set_border_style(BS_COMBO); 608 pPopup->actions()->set_actions(WA_COMBO); 609 pPopup->add(&sListBox); 610 pPopup->slots()->bind(LSPSLOT_MOUSE_DOWN, slot_on_list_mouse_down, self()); 611 pPopup->slots()->intercept(LSPSLOT_KEY_DOWN, slot_on_list_key_down, self()); 612 pPopup->slots()->bind(LSPSLOT_SHOW, slot_on_list_show, self()); 613 } 614 615 // Calculate popup window size and location 616 realize_t r; 617 r.nLeft = 0; 618 r.nTop = 0; 619 r.nWidth = 0; 620 r.nHeight = 0; 621 if (parent != NULL) 622 parent->get_absolute_geometry(&r); 623 624 // Get the screen size 625 ssize_t sw, sh; 626 size_t screen = pDisplay->display()->default_screen(); 627 LSPWindow *top = widget_cast<LSPWindow>(toplevel()); 628 if (top != NULL) 629 screen = top->screen(); 630 pDisplay->screen_size(screen, &sw, &sh); 631 632 // Get initial geometry of the window 633 size_request_t opr; 634 realize_t wr1, wr2; 635 636 sListBox.optimal_size_request(&opr); 637 638 wr1.nLeft = r.nLeft + sGroupHdr.nLeft; 639 if (wr1.nLeft < 0) 640 wr1.nLeft = 0; 641 wr1.nWidth = opr.nMaxWidth; 642 643 if ((wr1.nWidth < sGroupHdr.nWidth) && (sGroupHdr.nHeight < sw)) 644 wr1.nWidth = sGroupHdr.nWidth; 645 if (wr1.nWidth > sw) 646 wr1.nWidth = sw; 647 if (wr1.nHeight > sh) 648 wr1.nHeight = sh; 649 if ((wr1.nLeft + wr1.nWidth) >= sw) 650 { 651 wr1.nLeft = sw - wr1.nWidth; 652 if (wr1.nLeft < 0) 653 wr1.nLeft = 0; 654 } 655 wr2.nLeft = wr1.nLeft; 656 wr2.nWidth = wr1.nWidth; 657 658 wr1.nTop = r.nTop + sGroupHdr.nTop + sGroupHdr.nHeight; 659 wr2.nTop = 0; 660 661 wr1.nHeight = sh - wr1.nTop; 662 wr2.nHeight = r.nTop + sGroupHdr.nTop - wr2.nTop; 663 664 if (wr1.nHeight > opr.nMaxHeight) 665 wr1.nHeight = opr.nMaxHeight; 666 if (wr2.nHeight > opr.nMaxHeight) 667 { 668 wr2.nTop += wr2.nHeight - opr.nMaxHeight; 669 wr2.nHeight = opr.nMaxHeight; 670 } 671 672 if ((wr1.nHeight < opr.nMinHeight) && (wr2.nHeight >= opr.nMinHeight)) 673 pPopup->set_geometry(&wr2); 674 else 675 pPopup->set_geometry(&wr1); 676 677 // Finally, show the popup window 678 sListBox.show(); 679 sListBox.set_focus(); 680 pPopup->show(this); 681 pPopup->grab_events(GRAB_DROPDOWN); 682 nCBFlags |= F_OPENED; 683 684 return STATUS_OK; 685 } 686 set_circular(bool circular)687 void LSPComboGroup::set_circular(bool circular) 688 { 689 if (circular) 690 nCBFlags |= F_CIRCULAR; 691 else 692 nCBFlags &= ~F_CIRCULAR; 693 } 694 set_embed(bool embed)695 void LSPComboGroup::set_embed(bool embed) 696 { 697 if (bEmbed == embed) 698 return; 699 bEmbed = embed; 700 query_resize(); 701 } 702 on_list_change()703 status_t LSPComboGroup::on_list_change() 704 { 705 return sSlots.execute(LSPSLOT_CHANGE, this); 706 } 707 on_list_submit()708 status_t LSPComboGroup::on_list_submit() 709 { 710 if (!(nCBFlags & F_OPENED)) 711 return STATUS_OK; 712 close(); 713 return sSlots.execute(LSPSLOT_SUBMIT, this); 714 } 715 716 slot_on_change(LSPWidget * sender,void * ptr,void * data)717 status_t LSPComboGroup::slot_on_change(LSPWidget *sender, void *ptr, void *data) 718 { 719 LSPComboGroup *_this = widget_ptrcast<LSPComboGroup>(ptr); 720 return (ptr != NULL) ? _this->on_change() : STATUS_BAD_ARGUMENTS; 721 } 722 slot_on_submit(LSPWidget * sender,void * ptr,void * data)723 status_t LSPComboGroup::slot_on_submit(LSPWidget *sender, void *ptr, void *data) 724 { 725 LSPComboGroup *_this = widget_ptrcast<LSPComboGroup>(ptr); 726 return (ptr != NULL) ? _this->on_submit() : STATUS_BAD_ARGUMENTS; 727 } 728 slot_on_list_change(LSPWidget * sender,void * ptr,void * data)729 status_t LSPComboGroup::slot_on_list_change(LSPWidget *sender, void *ptr, void *data) 730 { 731 LSPComboGroup *_this = widget_ptrcast<LSPComboGroup>(ptr); 732 return (ptr != NULL) ? _this->on_list_change() : STATUS_BAD_ARGUMENTS; 733 } 734 slot_on_list_submit(LSPWidget * sender,void * ptr,void * data)735 status_t LSPComboGroup::slot_on_list_submit(LSPWidget *sender, void *ptr, void *data) 736 { 737 LSPComboGroup *_this = widget_ptrcast<LSPComboGroup>(ptr); 738 return (ptr != NULL) ? _this->on_list_submit() : STATUS_BAD_ARGUMENTS; 739 } 740 slot_on_list_focus_out(LSPWidget * sender,void * ptr,void * data)741 status_t LSPComboGroup::slot_on_list_focus_out(LSPWidget *sender, void *ptr, void *data) 742 { 743 LSPComboGroup *_this = widget_ptrcast<LSPComboGroup>(ptr); 744 return (ptr != NULL) ? _this->on_list_focus_out() : STATUS_BAD_ARGUMENTS; 745 } 746 slot_on_list_mouse_down(LSPWidget * sender,void * ptr,void * data)747 status_t LSPComboGroup::slot_on_list_mouse_down(LSPWidget *sender, void *ptr, void *data) 748 { 749 LSPComboGroup *_this = widget_ptrcast<LSPComboGroup>(ptr); 750 return (ptr != NULL) ? _this->on_grab_mouse_down(static_cast<ws_event_t *>(data)) : STATUS_BAD_ARGUMENTS; 751 } 752 slot_on_list_key_down(LSPWidget * sender,void * ptr,void * data)753 status_t LSPComboGroup::slot_on_list_key_down(LSPWidget *sender, void *ptr, void *data) 754 { 755 LSPComboGroup *_this = widget_ptrcast<LSPComboGroup>(ptr); 756 return (ptr != NULL) ? _this->on_grab_key_down(static_cast<ws_event_t *>(data)) : STATUS_BAD_ARGUMENTS; 757 } 758 slot_on_list_show(LSPWidget * sender,void * ptr,void * data)759 status_t LSPComboGroup::slot_on_list_show(LSPWidget *sender, void *ptr, void *data) 760 { 761 LSPComboGroup *_this = widget_ptrcast<LSPComboGroup>(ptr); 762 return (ptr != NULL) ? _this->on_list_show() : STATUS_BAD_ARGUMENTS; 763 } 764 on_selection_change()765 void LSPComboGroup::on_selection_change() 766 { 767 query_resize(); 768 // query_draw(); 769 } 770 on_item_change(size_t index,LSPItem * item)771 void LSPComboGroup::on_item_change(size_t index, LSPItem *item) 772 { 773 ssize_t sel = sListBox.selection()->value(); 774 if ((sel >= 0) && (index == size_t(sel))) 775 query_draw(); 776 } 777 on_item_add(size_t index)778 void LSPComboGroup::on_item_add(size_t index) 779 { 780 } 781 on_item_remove(size_t index)782 void LSPComboGroup::on_item_remove(size_t index) 783 { 784 ssize_t sel = sListBox.selection()->value(); 785 if ((sel >= 0) && (index == size_t(sel))) 786 query_draw(); 787 } 788 on_item_swap(size_t idx1,size_t idx2)789 void LSPComboGroup::on_item_swap(size_t idx1, size_t idx2) 790 { 791 ssize_t sel = sListBox.selection()->value(); 792 if (sel < 0) 793 return; 794 if ((idx1 == size_t(sel)) || (idx2 == size_t(sel))) 795 query_draw(); 796 } 797 on_item_clear()798 void LSPComboGroup::on_item_clear() 799 { 800 query_draw(); 801 } 802 on_list_focus_out()803 status_t LSPComboGroup::on_list_focus_out() 804 { 805 lsp_trace("focus_out triggered"); 806 return STATUS_OK; 807 } 808 on_list_show()809 status_t LSPComboGroup::on_list_show() 810 { 811 // if (pPopup != NULL) 812 // pPopup->take_focus(); 813 return STATUS_OK; 814 } 815 on_grab_mouse_down(const ws_event_t * e)816 status_t LSPComboGroup::on_grab_mouse_down(const ws_event_t *e) 817 { 818 lsp_trace("mouse_down triggered left=%d, top=%d", int(e->nLeft), int(e->nTop)); 819 if ((e->nLeft < 0) || (e->nTop < 0) || (e->nLeft > pPopup->width()) || (e->nTop > pPopup->height())) 820 close(); 821 822 return STATUS_OK; 823 } 824 on_grab_key_down(const ws_event_t * e)825 status_t LSPComboGroup::on_grab_key_down(const ws_event_t *e) 826 { 827 lsp_trace("key_down triggered left=%d, top=%d", int(e->nLeft), int(e->nTop)); 828 close(); 829 return STATUS_OK; 830 } 831 } /* namespace tk */ 832 } /* namespace lsp */ 833