| 403 char *name = args->name ? (char*)args->name : "textfield"; |
406 char *name = args->name ? (char*)args->name : "textfield"; |
| 404 Widget textfield = XmCreateTextField(parent, name, xargs, n); |
407 Widget textfield = XmCreateTextField(parent, name, xargs, n); |
| 405 XtManageChild(textfield); |
408 XtManageChild(textfield); |
| 406 ui_container_add(ctn, textfield); |
409 ui_container_add(ctn, textfield); |
| 407 |
410 |
| 408 ui_set_widget_groups(obj->ctx, textfield, args->groups); |
411 ui_set_widget_groups(obj->ctx, textfield, args->states); |
| |
412 |
| |
413 UiEventDataExt *eventdata = malloc(sizeof(UiEventDataExt)); |
| |
414 memset(eventdata, 0, sizeof(UiEventDataExt)); |
| |
415 eventdata->obj = obj; |
| |
416 eventdata->callback = args->onactivate; |
| |
417 eventdata->userdata = args->onactivatedata; |
| |
418 eventdata->callback2 = args->onchange; |
| |
419 eventdata->userdata2 = args->onchangedata; |
| 409 |
420 |
| 410 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING); |
421 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING); |
| 411 if(var) { |
422 if(var) { |
| |
423 eventdata->customdata0 = var; |
| |
424 |
| 412 UiString *value = (UiString*)var->value; |
425 UiString *value = (UiString*)var->value; |
| 413 value->obj = textfield; |
426 value->obj = textfield; |
| 414 value->get = ui_textfield_get; |
427 value->get = ui_textfield_get; |
| 415 value->set = ui_textfield_set; |
428 value->set = ui_textfield_set; |
| 416 |
429 |
| 417 if(value->value.ptr) { |
430 if(value->value.ptr) { |
| 418 ui_textfield_set(value, value->value.ptr); |
431 ui_textfield_set(value, value->value.ptr); |
| 419 } |
432 } |
| 420 } |
433 } |
| 421 |
434 |
| |
435 XtAddCallback( |
| |
436 textfield, |
| |
437 XmNactivateCallback, |
| |
438 (XtCallbackProc)ui_textfield_activate, |
| |
439 eventdata); |
| |
440 XtAddCallback( |
| |
441 textfield, |
| |
442 XmNvalueChangedCallback, |
| |
443 (XtCallbackProc)ui_textfield_value_changed, |
| |
444 eventdata); |
| |
445 XtAddCallback( |
| |
446 textfield, |
| |
447 XmNdestroyCallback, |
| |
448 (XtCallbackProc)ui_destroy_data, |
| |
449 eventdata); |
| |
450 |
| 422 return textfield; |
451 return textfield; |
| |
452 } |
| |
453 |
| |
454 static void textfield_event(UiEventDataExt *eventdata, ui_callback callback, void *userdata) { |
| |
455 if(callback) { |
| |
456 UiVar *var = eventdata->customdata0; |
| |
457 UiString *value = var ? var->value : NULL; |
| |
458 |
| |
459 UiEvent e; |
| |
460 e.obj = eventdata->obj; |
| |
461 e.window = e.obj->window; |
| |
462 e.document = e.obj->ctx->document; |
| |
463 e.eventdata = value; |
| |
464 e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0; |
| |
465 e.intval = 0; |
| |
466 e.set = ui_get_setop(); |
| |
467 callback(&e, userdata); |
| |
468 } |
| |
469 } |
| |
470 |
| |
471 void ui_textfield_activate(Widget widget, XtPointer ud, XtPointer cb) { |
| |
472 UiEventDataExt *eventdata = ud; |
| |
473 textfield_event(ud, eventdata->callback, eventdata->userdata); |
| |
474 } |
| |
475 |
| |
476 void ui_textfield_value_changed(Widget widget, XtPointer ud, XtPointer cb) { |
| |
477 UiEventDataExt *eventdata = ud; |
| |
478 if(ui_onchange_events_is_enabled()) { |
| |
479 textfield_event(ud, eventdata->callback2, eventdata->userdata2); |
| |
480 } |
| 423 } |
481 } |
| 424 |
482 |
| 425 UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs *args) { |
483 UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs *args) { |
| 426 return create_textfield(obj, args, FALSE, FALSE); |
484 return create_textfield(obj, args, FALSE, FALSE); |
| 427 } |
485 } |
| 448 XmTextFieldSetString(str->obj, (void*)value); |
506 XmTextFieldSetString(str->obj, (void*)value); |
| 449 if(str->value.free) { |
507 if(str->value.free) { |
| 450 str->value.free(str->value.ptr); |
508 str->value.free(str->value.ptr); |
| 451 } |
509 } |
| 452 str->value.ptr = NULL; |
510 str->value.ptr = NULL; |
| 453 } |
|
| 454 |
|
| 455 |
|
| 456 |
|
| 457 |
|
| 458 |
|
| 459 /* -------------------- path bar -------------------- */ |
|
| 460 |
|
| 461 #define XNECreateText(parent,name,args,count) XmCreateTextField(parent,name,args,count) |
|
| 462 #define XNETextSetString(widget,value) XmTextFieldSetString(widget,value) |
|
| 463 #define XNETextGetString(widget) XmTextFieldGetString(widget) |
|
| 464 #define XNETextGetLastPosition(widget) XmTextFieldGetLastPosition(widget) |
|
| 465 #define XNETextSetInsertionPosition(widget, i) XmTextFieldSetInsertionPosition(widget, i) |
|
| 466 #define XNETextSetSelection(w, f, l, t) XmTextFieldSetSelection(w, f, l, t) |
|
| 467 |
|
| 468 typedef void(*updatedir_callback)(void*,char*,int); |
|
| 469 |
|
| 470 typedef struct PathBar { |
|
| 471 Widget widget; |
|
| 472 Widget textfield; |
|
| 473 |
|
| 474 Widget focus_widget; |
|
| 475 |
|
| 476 Widget left; |
|
| 477 Widget right; |
|
| 478 Dimension lw; |
|
| 479 Dimension rw; |
|
| 480 |
|
| 481 int shift; |
|
| 482 |
|
| 483 UiPathElm *current_pathelms; |
|
| 484 Widget *pathSegments; |
|
| 485 size_t numSegments; |
|
| 486 size_t segmentAlloc; |
|
| 487 |
|
| 488 char *path; |
|
| 489 int selection; |
|
| 490 Boolean input; |
|
| 491 |
|
| 492 int focus; |
|
| 493 |
|
| 494 updatedir_callback updateDir; |
|
| 495 void *updateDirData; |
|
| 496 |
|
| 497 ui_pathelm_func getpathelm; |
|
| 498 void *getpathelmdata; |
|
| 499 } PathBar; |
|
| 500 |
|
| 501 void PathBarSetPath(PathBar *bar, const char *path); |
|
| 502 |
|
| 503 void pathbar_resize(Widget w, PathBar *p, XtPointer d) |
|
| 504 { |
|
| 505 Dimension width, height; |
|
| 506 XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL); |
|
| 507 |
|
| 508 Dimension *segW = (void*)XtCalloc(p->numSegments, sizeof(Dimension)); |
|
| 509 |
|
| 510 Dimension maxHeight = 0; |
|
| 511 |
|
| 512 /* get width/height from all widgets */ |
|
| 513 Dimension pathWidth = 0; |
|
| 514 for(int i=0;i<p->numSegments;i++) { |
|
| 515 Dimension segWidth; |
|
| 516 Dimension segHeight; |
|
| 517 XtVaGetValues(p->pathSegments[i], XmNwidth, &segWidth, XmNheight, &segHeight, NULL); |
|
| 518 segW[i] = segWidth; |
|
| 519 pathWidth += segWidth; |
|
| 520 if(segHeight > maxHeight) { |
|
| 521 maxHeight = segHeight; |
|
| 522 } |
|
| 523 } |
|
| 524 Dimension tfHeight; |
|
| 525 XtVaGetValues(p->textfield, XmNheight, &tfHeight, NULL); |
|
| 526 if(tfHeight > maxHeight) { |
|
| 527 maxHeight = tfHeight; |
|
| 528 } |
|
| 529 |
|
| 530 Boolean arrows = False; |
|
| 531 if(pathWidth + 10 > width) { |
|
| 532 arrows = True; |
|
| 533 pathWidth += p->lw + p->rw; |
|
| 534 } |
|
| 535 |
|
| 536 /* calc max visible widgets */ |
|
| 537 int start = 0; |
|
| 538 if(arrows) { |
|
| 539 Dimension vis = p->lw+p->rw; |
|
| 540 for(int i=p->numSegments;i>0;i--) { |
|
| 541 Dimension segWidth = segW[i-1]; |
|
| 542 if(vis + segWidth + 10 > width) { |
|
| 543 start = i; |
|
| 544 arrows = True; |
|
| 545 break; |
|
| 546 } |
|
| 547 vis += segWidth; |
|
| 548 } |
|
| 549 } else { |
|
| 550 p->shift = 0; |
|
| 551 } |
|
| 552 |
|
| 553 int leftShift = 0; |
|
| 554 if(p->shift < 0) { |
|
| 555 if(start + p->shift < 0) { |
|
| 556 leftShift = start; |
|
| 557 start = 0; |
|
| 558 p->shift = -leftShift; |
|
| 559 } else { |
|
| 560 leftShift = -p->shift; /* negative shift */ |
|
| 561 start += p->shift; |
|
| 562 } |
|
| 563 } |
|
| 564 |
|
| 565 int x = 0; |
|
| 566 if(arrows) { |
|
| 567 XtManageChild(p->left); |
|
| 568 XtManageChild(p->right); |
|
| 569 x = p->lw; |
|
| 570 } else { |
|
| 571 XtUnmanageChild(p->left); |
|
| 572 XtUnmanageChild(p->right); |
|
| 573 } |
|
| 574 |
|
| 575 for(int i=0;i<p->numSegments;i++) { |
|
| 576 if(i >= start && i < p->numSegments - leftShift && !p->input) { |
|
| 577 XtVaSetValues(p->pathSegments[i], XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL); |
|
| 578 x += segW[i]; |
|
| 579 XtManageChild(p->pathSegments[i]); |
|
| 580 } else { |
|
| 581 XtUnmanageChild(p->pathSegments[i]); |
|
| 582 } |
|
| 583 } |
|
| 584 |
|
| 585 if(arrows) { |
|
| 586 XtVaSetValues(p->left, XmNx, 0, XmNy, 0, XmNheight, maxHeight, NULL); |
|
| 587 XtVaSetValues(p->right, XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL); |
|
| 588 } |
|
| 589 |
|
| 590 free(segW); |
|
| 591 |
|
| 592 Dimension rw, rh; |
|
| 593 XtMakeResizeRequest(w, width, maxHeight, &rw, &rh); |
|
| 594 |
|
| 595 XtVaSetValues(p->textfield, XmNwidth, rw, XmNheight, rh, NULL); |
|
| 596 } |
|
| 597 |
|
| 598 static void pathbarActivateTF(PathBar *p) |
|
| 599 { |
|
| 600 XtUnmanageChild(p->left); |
|
| 601 XtUnmanageChild(p->right); |
|
| 602 XNETextSetSelection(p->textfield, 0, XNETextGetLastPosition(p->textfield), 0); |
|
| 603 XtManageChild(p->textfield); |
|
| 604 p->input = 1; |
|
| 605 |
|
| 606 XmProcessTraversal(p->textfield, XmTRAVERSE_CURRENT); |
|
| 607 |
|
| 608 pathbar_resize(p->widget, p, NULL); |
|
| 609 } |
|
| 610 |
|
| 611 void PathBarActivateTextfield(PathBar *p) |
|
| 612 { |
|
| 613 p->focus = 1; |
|
| 614 pathbarActivateTF(p); |
|
| 615 } |
|
| 616 |
|
| 617 void pathbar_input(Widget w, PathBar *p, XtPointer c) |
|
| 618 { |
|
| 619 XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*)c; |
|
| 620 XEvent *xevent = cbs->event; |
|
| 621 |
|
| 622 if (cbs->reason == XmCR_INPUT) { |
|
| 623 if (xevent->xany.type == ButtonPress) { |
|
| 624 p->focus = 0; |
|
| 625 pathbarActivateTF(p); |
|
| 626 } |
|
| 627 } |
|
| 628 } |
|
| 629 |
|
| 630 void pathbar_losingfocus(Widget w, PathBar *p, XtPointer c) |
|
| 631 { |
|
| 632 if(--p->focus < 0) { |
|
| 633 p->input = False; |
|
| 634 XtUnmanageChild(p->textfield); |
|
| 635 } |
|
| 636 } |
|
| 637 |
|
| 638 static cxmutstr concat_path_s(cxstring base, cxstring path) { |
|
| 639 if(!path.ptr) { |
|
| 640 path = CX_STR(""); |
|
| 641 } |
|
| 642 |
|
| 643 int add_separator = 0; |
|
| 644 if(base.length != 0 && base.ptr[base.length-1] == '/') { |
|
| 645 if(path.ptr[0] == '/') { |
|
| 646 base.length--; |
|
| 647 } |
|
| 648 } else { |
|
| 649 if(path.length == 0 || path.ptr[0] != '/') { |
|
| 650 add_separator = 1; |
|
| 651 } |
|
| 652 } |
|
| 653 |
|
| 654 cxmutstr url; |
|
| 655 if(add_separator) { |
|
| 656 url = cx_strcat(3, base, CX_STR("/"), path); |
|
| 657 } else { |
|
| 658 url = cx_strcat(2, base, path); |
|
| 659 } |
|
| 660 |
|
| 661 return url; |
|
| 662 } |
|
| 663 |
|
| 664 static char* ConcatPath(const char *path1, const char *path2) { |
|
| 665 return concat_path_s(cx_str(path1), cx_str(path2)).ptr; |
|
| 666 } |
|
| 667 |
|
| 668 void pathbar_pathinput(Widget w, PathBar *p, XtPointer d) |
|
| 669 { |
|
| 670 char *newpath = XNETextGetString(p->textfield); |
|
| 671 if(newpath) { |
|
| 672 if(newpath[0] == '~') { |
|
| 673 char *p = newpath+1; |
|
| 674 char *home = getenv("HOME"); |
|
| 675 char *cp = ConcatPath(home, p); |
|
| 676 XtFree(newpath); |
|
| 677 newpath = cp; |
|
| 678 } else if(newpath[0] != '/') { |
|
| 679 char curdir[2048]; |
|
| 680 curdir[0] = 0; |
|
| 681 getcwd(curdir, 2048); |
|
| 682 char *cp = ConcatPath(curdir, newpath); |
|
| 683 XtFree(newpath); |
|
| 684 newpath = cp; |
|
| 685 } |
|
| 686 |
|
| 687 /* update path */ |
|
| 688 PathBarSetPath(p, newpath); |
|
| 689 if(p->updateDir) { |
|
| 690 p->updateDir(p->updateDirData, newpath, -1); |
|
| 691 } |
|
| 692 XtFree(newpath); |
|
| 693 |
|
| 694 /* hide textfield and show path as buttons */ |
|
| 695 XtUnmanageChild(p->textfield); |
|
| 696 pathbar_resize(p->widget, p, NULL); |
|
| 697 |
|
| 698 if(p->focus_widget) { |
|
| 699 XmProcessTraversal(p->focus_widget, XmTRAVERSE_CURRENT); |
|
| 700 } |
|
| 701 } |
|
| 702 } |
|
| 703 |
|
| 704 void pathbar_shift_left(Widget w, PathBar *p, XtPointer d) |
|
| 705 { |
|
| 706 p->shift--; |
|
| 707 pathbar_resize(p->widget, p, NULL); |
|
| 708 } |
|
| 709 |
|
| 710 void pathbar_shift_right(Widget w, PathBar *p, XtPointer d) |
|
| 711 { |
|
| 712 if(p->shift < 0) { |
|
| 713 p->shift++; |
|
| 714 } |
|
| 715 pathbar_resize(p->widget, p, NULL); |
|
| 716 } |
|
| 717 |
|
| 718 static void pathTextEH(Widget widget, XtPointer data, XEvent *event, Boolean *dispatch) { |
|
| 719 PathBar *pb = data; |
|
| 720 if(event->type == KeyReleaseMask) { |
|
| 721 if(event->xkey.keycode == 9) { |
|
| 722 XtUnmanageChild(pb->textfield); |
|
| 723 pathbar_resize(pb->widget, pb, NULL); |
|
| 724 *dispatch = False; |
|
| 725 } else if(event->xkey.keycode == 36) { |
|
| 726 pathbar_pathinput(pb->textfield, pb, NULL); |
|
| 727 *dispatch = False; |
|
| 728 } |
|
| 729 } |
|
| 730 } |
|
| 731 |
|
| 732 PathBar* CreatePathBar(Widget parent, ArgList args, int n) |
|
| 733 { |
|
| 734 PathBar *bar = (PathBar*)XtMalloc(sizeof(PathBar)); |
|
| 735 bar->path = NULL; |
|
| 736 bar->updateDir = NULL; |
|
| 737 bar->updateDirData = NULL; |
|
| 738 |
|
| 739 bar->focus_widget = NULL; |
|
| 740 |
|
| 741 bar->getpathelm = NULL; |
|
| 742 bar->getpathelmdata = NULL; |
|
| 743 bar->current_pathelms = NULL; |
|
| 744 |
|
| 745 bar->shift = 0; |
|
| 746 |
|
| 747 XtSetArg(args[n], XmNmarginWidth, 0); n++; |
|
| 748 XtSetArg(args[n], XmNmarginHeight, 0); n++; |
|
| 749 bar->widget = XmCreateDrawingArea(parent, "pathbar", args, n); |
|
| 750 XtAddCallback( |
|
| 751 bar->widget, |
|
| 752 XmNresizeCallback, |
|
| 753 (XtCallbackProc)pathbar_resize, |
|
| 754 bar); |
|
| 755 XtAddCallback( |
|
| 756 bar->widget, |
|
| 757 XmNinputCallback, |
|
| 758 (XtCallbackProc)pathbar_input, |
|
| 759 bar); |
|
| 760 |
|
| 761 Arg a[4]; |
|
| 762 XtSetArg(a[0], XmNshadowThickness, 0); |
|
| 763 XtSetArg(a[1], XmNx, 0); |
|
| 764 XtSetArg(a[2], XmNy, 0); |
|
| 765 bar->textfield = XNECreateText(bar->widget, "pbtext", a, 3); |
|
| 766 bar->input = 0; |
|
| 767 XtAddCallback( |
|
| 768 bar->textfield, |
|
| 769 XmNlosingFocusCallback, |
|
| 770 (XtCallbackProc)pathbar_losingfocus, |
|
| 771 bar); |
|
| 772 XtAddCallback(bar->textfield, XmNactivateCallback, |
|
| 773 (XtCallbackProc)pathbar_pathinput, bar); |
|
| 774 XtAddEventHandler(bar->textfield, KeyPressMask | KeyReleaseMask, FALSE, pathTextEH, bar); |
|
| 775 |
|
| 776 XtSetArg(a[0], XmNarrowDirection, XmARROW_LEFT); |
|
| 777 bar->left = XmCreateArrowButton(bar->widget, "pbbutton", a, 1); |
|
| 778 XtSetArg(a[0], XmNarrowDirection, XmARROW_RIGHT); |
|
| 779 bar->right = XmCreateArrowButton(bar->widget, "pbbutton", a, 1); |
|
| 780 XtAddCallback( |
|
| 781 bar->left, |
|
| 782 XmNactivateCallback, |
|
| 783 (XtCallbackProc)pathbar_shift_left, |
|
| 784 bar); |
|
| 785 XtAddCallback( |
|
| 786 bar->right, |
|
| 787 XmNactivateCallback, |
|
| 788 (XtCallbackProc)pathbar_shift_right, |
|
| 789 bar); |
|
| 790 |
|
| 791 Pixel bg; |
|
| 792 XtVaGetValues(bar->textfield, XmNbackground, &bg, NULL); |
|
| 793 XtVaSetValues(bar->widget, XmNbackground, bg, NULL); |
|
| 794 |
|
| 795 XtManageChild(bar->left); |
|
| 796 XtManageChild(bar->right); |
|
| 797 |
|
| 798 XtVaGetValues(bar->left, XmNwidth, &bar->lw, NULL); |
|
| 799 XtVaGetValues(bar->right, XmNwidth, &bar->rw, NULL); |
|
| 800 |
|
| 801 bar->segmentAlloc = 16; |
|
| 802 bar->numSegments = 0; |
|
| 803 bar->pathSegments = (Widget*)XtCalloc(16, sizeof(Widget)); |
|
| 804 |
|
| 805 bar->selection = 0; |
|
| 806 |
|
| 807 return bar; |
|
| 808 } |
|
| 809 |
|
| 810 void PathBarChangeDir(Widget w, PathBar *bar, XtPointer c) |
|
| 811 { |
|
| 812 XmToggleButtonSetState(bar->pathSegments[bar->selection], False, False); |
|
| 813 |
|
| 814 int i; |
|
| 815 for(i=0;i<bar->numSegments;i++) { |
|
| 816 if(bar->pathSegments[i] == w) { |
|
| 817 bar->selection = i; |
|
| 818 XmToggleButtonSetState(w, True, False); |
|
| 819 break; |
|
| 820 } |
|
| 821 } |
|
| 822 |
|
| 823 UiPathElm elm = bar->current_pathelms[i]; |
|
| 824 cxmutstr path = cx_strdup(cx_strn(elm.path, elm.path_len)); |
|
| 825 if(bar->updateDir) { |
|
| 826 XNETextSetString(bar->textfield, path.ptr); |
|
| 827 bar->updateDir(bar->updateDirData, path.ptr, i); |
|
| 828 } |
|
| 829 free(path.ptr); |
|
| 830 } |
|
| 831 |
|
| 832 static void ui_pathelm_destroy(UiPathElm *elms, size_t nelm) { |
|
| 833 for(int i=0;i<nelm;i++) { |
|
| 834 free(elms[i].name); |
|
| 835 free(elms[i].path); |
|
| 836 } |
|
| 837 free(elms); |
|
| 838 } |
|
| 839 |
|
| 840 void PathBarSetPath(PathBar *bar, const char *path) |
|
| 841 { |
|
| 842 if(bar->path) { |
|
| 843 free(bar->path); |
|
| 844 } |
|
| 845 bar->path = strdup(path); |
|
| 846 |
|
| 847 for(int i=0;i<bar->numSegments;i++) { |
|
| 848 XtDestroyWidget(bar->pathSegments[i]); |
|
| 849 } |
|
| 850 XtUnmanageChild(bar->textfield); |
|
| 851 XtManageChild(bar->left); |
|
| 852 XtManageChild(bar->right); |
|
| 853 bar->input = False; |
|
| 854 |
|
| 855 Arg args[4]; |
|
| 856 XmString str; |
|
| 857 |
|
| 858 bar->numSegments = 0; |
|
| 859 |
|
| 860 ui_pathelm_destroy(bar->current_pathelms, bar->numSegments); |
|
| 861 size_t nelm = 0; |
|
| 862 UiPathElm* path_elm = bar->getpathelm(bar->path, strlen(bar->path), &nelm, bar->getpathelmdata); |
|
| 863 if (!path_elm) { |
|
| 864 return; |
|
| 865 } |
|
| 866 bar->current_pathelms = path_elm; |
|
| 867 bar->numSegments = nelm; |
|
| 868 bar->pathSegments = realloc(bar->pathSegments, nelm * sizeof(Widget*)); |
|
| 869 |
|
| 870 for(int i=0;i<nelm;i++) { |
|
| 871 UiPathElm elm = path_elm[i]; |
|
| 872 |
|
| 873 cxmutstr name = cx_strdup(cx_strn(elm.name, elm.name_len)); |
|
| 874 str = XmStringCreateLocalized(elm.name); |
|
| 875 free(name.ptr); |
|
| 876 |
|
| 877 XtSetArg(args[0], XmNlabelString, str); |
|
| 878 XtSetArg(args[1], XmNfillOnSelect, True); |
|
| 879 XtSetArg(args[2], XmNindicatorOn, False); |
|
| 880 Widget button = XmCreateToggleButton(bar->widget, "pbbutton", args, 3); |
|
| 881 XtAddCallback( |
|
| 882 button, |
|
| 883 XmNvalueChangedCallback, |
|
| 884 (XtCallbackProc)PathBarChangeDir, |
|
| 885 bar); |
|
| 886 XmStringFree(str); |
|
| 887 |
|
| 888 bar->pathSegments[i] = button; |
|
| 889 } |
|
| 890 |
|
| 891 bar->selection = bar->numSegments-1; |
|
| 892 XmToggleButtonSetState(bar->pathSegments[bar->selection], True, False); |
|
| 893 |
|
| 894 XNETextSetString(bar->textfield, (char*)path); |
|
| 895 XNETextSetInsertionPosition(bar->textfield, XNETextGetLastPosition(bar->textfield)); |
|
| 896 |
|
| 897 pathbar_resize(bar->widget, bar, NULL); |
|
| 898 } |
|
| 899 |
|
| 900 void PathBarDestroy(PathBar *pathbar) { |
|
| 901 if(pathbar->path) { |
|
| 902 XtFree(pathbar->path); |
|
| 903 } |
|
| 904 XtFree((void*)pathbar->pathSegments); |
|
| 905 XtFree((void*)pathbar); |
|
| 906 } |
511 } |
| 907 |
512 |
| 908 |
513 |
| 909 /* ---------------------------- Path Text Field ---------------------------- */ |
514 /* ---------------------------- Path Text Field ---------------------------- */ |
| 910 |
515 |
| 911 static void destroy_pathbar(Widget w, XtPointer *data, XtPointer d) { |
516 static void destroy_pathbar(Widget w, XtPointer *data, XtPointer d) { |
| 912 PathBar *pathbar = (PathBar*)data; |
517 PathBar *pathbar = (PathBar*)data; |
| 913 // TODO: check if there is somonething missing |
518 // TODO: check if there is somonething missing |
| 914 XtFree((void*)pathbar->pathSegments); |
519 XtFree((void*)pathbar->pathSegments); |
| 915 XtFree((void*)pathbar); |
520 XtFree((void*)pathbar); |
| 916 } |
|
| 917 |
|
| 918 // TODO: move to common |
|
| 919 static UiPathElm* default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data) { |
|
| 920 cxstring *pathelms; |
|
| 921 size_t nelm = cx_strsplit_a(cxDefaultAllocator, cx_strn(full_path, len), CX_STR("/"), 4096, &pathelms); |
|
| 922 |
|
| 923 if (nelm == 0) { |
|
| 924 *ret_nelm = 0; |
|
| 925 return NULL; |
|
| 926 } |
|
| 927 |
|
| 928 UiPathElm* elms = (UiPathElm*)calloc(nelm, sizeof(UiPathElm)); |
|
| 929 size_t n = nelm; |
|
| 930 int j = 0; |
|
| 931 for (int i = 0; i < nelm; i++) { |
|
| 932 cxstring c = pathelms[i]; |
|
| 933 if (c.length == 0) { |
|
| 934 if (i == 0) { |
|
| 935 c.length = 1; |
|
| 936 } |
|
| 937 else { |
|
| 938 n--; |
|
| 939 continue; |
|
| 940 } |
|
| 941 } |
|
| 942 |
|
| 943 cxmutstr m = cx_strdup(c); |
|
| 944 elms[j].name = m.ptr; |
|
| 945 elms[j].name_len = m.length; |
|
| 946 |
|
| 947 size_t elm_path_len = c.ptr + c.length - full_path; |
|
| 948 cxmutstr elm_path = cx_strdup(cx_strn(full_path, elm_path_len)); |
|
| 949 elms[j].path = elm_path.ptr; |
|
| 950 elms[j].path_len = elm_path.length; |
|
| 951 |
|
| 952 j++; |
|
| 953 } |
|
| 954 *ret_nelm = n; |
|
| 955 |
|
| 956 return elms; |
|
| 957 } |
521 } |
| 958 |
522 |
| 959 static void pathbar_activate(void *data, char *path, int index) { |
523 static void pathbar_activate(void *data, char *path, int index) { |
| 960 UiEventData *event = data; |
524 UiEventData *event = data; |
| 961 UiEvent evt; |
525 UiEvent evt; |