#include "pch.h"
#include "text.h"
#include "../common/context.h"
#include "../common/object.h"
#include <cx/string.h>
#include <cx/allocator.h>
#include "util.h"
#include "container.h"
using namespace winrt;
using namespace Microsoft::
UI::Xaml;
using namespace Microsoft::
UI::Xaml::Controls;
using namespace Windows::
UI::Xaml::Interop;
using namespace winrt::Windows::Foundation;
using namespace Microsoft::
UI::Xaml::Markup;
using namespace Microsoft::
UI::Xaml::Media;
using namespace winrt::Microsoft::
UI::Xaml::Controls::Primitives;
using namespace winrt::Windows::
UI::Xaml::Input;
UIEXPORT UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) {
UiObject* current = uic_current_obj(obj);
TextBox textarea = TextBox();
textarea.AcceptsReturn(true);
ScrollViewer::SetVerticalScrollBarVisibility(textarea, ScrollBarVisibility::Auto);
UIElement elm = textarea;
UiWidget* widget = new UiWidget(elm);
ui_context_add_widget_destructor(current->ctx, widget);
ui_set_widget_groups(current->ctx, widget, args.groups);
UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname,
UI_VAR_TEXT);
if (var) {
UiText* value = (UiText*)var->value;
value->obj = widget;
value->undomgr =
NULL;
value->set = ui_textarea_set;
value->get = ui_textarea_get;
value->getsubstr = ui_textarea_getsubstr;
value->insert = ui_textarea_insert;
value->setposition = ui_textarea_setposition;
value->position = ui_textarea_position;
value->selection = ui_textarea_selection;
value->length = ui_textarea_length;
value->remove = ui_textarea_remove;
}
UI_APPLY_LAYOUT1(current, args);
current->container->Add(textarea, true);
return widget;
}
UIEXPORT UIWIDGET ui_textarea_gettextwidget(
UIWIDGET textarea) {
return textarea;
}
UIEXPORT void ui_text_undo(UiText *value) {
}
UIEXPORT void ui_text_redo(UiText *value) {
}
char* ui_wtext_get(UiText *text, std::wstring &value) {
if (text->value.ptr) {
text->value.free(text->value.ptr);
}
text->value.ptr = wchar2utf8(value.c_str(), value.length());
text->value.free = free;
return text->value.ptr;
}
std::wstring ui_wtext_set(UiText *text,
const char* value) {
if (text->value.ptr) {
text->value.free(text->value.ptr);
}
text->value.ptr = _strdup(value);
text->value.free = free;
int len;
wchar_t* wstr = str2wstr(value, &len);
std::wstring s(wstr);
free(wstr);
return s;
}
extern "C" char* ui_textarea_get(UiText *text) {
UiWidget* widget = (UiWidget*)text->obj;
TextBox box = widget->uielement.as<TextBox>();
std::wstring wstr(box.Text());
return ui_wtext_get(text, wstr);
}
extern "C" void ui_textarea_set(UiText *text,
const char *newvalue) {
UiWidget* widget = (UiWidget*)text->obj;
TextBox box = widget->uielement.as<TextBox>();
box.Text(ui_wtext_set(text, newvalue));
}
extern "C" char* ui_textarea_getsubstr(UiText *text,
int begin,
int end) {
return NULL;
}
extern "C" void ui_textarea_insert(UiText *text,
int pos,
char *str) {
}
extern "C" void ui_textarea_setposition(UiText *text,
int pos) {
}
extern "C" int ui_textarea_position(UiText *text) {
return 0;
}
extern "C" void ui_textarea_selection(UiText *text,
int *begin,
int *end) {
}
extern "C" int ui_textarea_length(UiText *text) {
return 0;
}
extern "C" void ui_textarea_remove(UiText *text,
int begin,
int end) {
}
UIWIDGET ui_textfield_create(UiObject* obj, UiTextFieldArgs args) {
UiObject* current = uic_current_obj(obj);
TextBox textfield = TextBox();
UIElement elm = textfield;
UiWidget* widget = new UiWidget(elm);
ui_context_add_widget_destructor(current->ctx, widget);
ui_set_widget_groups(current->ctx, widget, args.groups);
UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname,
UI_VAR_STRING);
if (var) {
UiString* value = (UiString*)var->value;
value->obj = widget;
value->get = ui_textfield_get;
value->set = ui_textfield_set;
}
UI_APPLY_LAYOUT1(current, args);
current->container->Add(textfield, false);
return widget;
}
UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args) {
return ui_textfield_create(obj, args);
}
UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) {
UiObject* current = uic_current_obj(obj);
PasswordBox textfield = PasswordBox();
UIElement elm = textfield;
UiWidget* widget = new UiWidget(elm);
ui_context_add_widget_destructor(current->ctx, widget);
ui_set_widget_groups(current->ctx, widget, args.groups);
UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname,
UI_VAR_STRING);
if (var) {
UiString* value = (UiString*)var->value;
value->obj = widget;
value->get = ui_passwordfield_get;
value->set = ui_passwordfield_set;
}
UI_APPLY_LAYOUT1(current, args);
current->container->Add(textfield, false);
return widget;
}
char* ui_wstring_get(UiString* str, std::wstring &value) {
if (str->value.ptr) {
str->value.free(str->value.ptr);
}
str->value.ptr = wchar2utf8(value.c_str(), value.length());
str->value.free = free;
return str->value.ptr;
}
std::wstring ui_wstring_set(UiString* str,
const char* value) {
if (str->value.ptr) {
str->value.free(str->value.ptr);
}
str->value.ptr = _strdup(value);
str->value.free = free;
int len;
wchar_t* wstr = str2wstr(value, &len);
std::wstring s(wstr);
free(wstr);
return s;
}
char* ui_textfield_get(UiString * str) {
UiWidget* widget = (UiWidget*)str->obj;
TextBox box = widget->uielement.as<TextBox>();
std::wstring wstr(box.Text());
return ui_wstring_get(str, wstr);
}
void ui_textfield_set(UiString * str,
const char* newvalue) {
UiWidget* widget = (UiWidget*)str->obj;
TextBox box = widget->uielement.as<TextBox>();
box.Text(ui_wstring_set(str, newvalue));
}
char* ui_passwordfield_get(UiString * str) {
UiWidget* widget = (UiWidget*)str->obj;
PasswordBox box = widget->uielement.as<PasswordBox>();
std::wstring wstr(box.Password());
return ui_wstring_get(str, wstr);
}
void ui_passwordfield_set(UiString * str,
const char* newvalue) {
UiWidget* widget = (UiWidget*)str->obj;
PasswordBox box = widget->uielement.as<PasswordBox>();
box.Password(ui_wstring_set(str, newvalue));
}
extern "C" static void destroy_ui_pathtextfield(
void* ptr) {
UiPathTextField* pb = (UiPathTextField*)ptr;
delete pb;
}
static void ui_context_add_pathtextfield_destructor(UiContext* ctx, UiPathTextField* pb) {
cxMempoolRegister(ctx->mp, pb, destroy_ui_pathtextfield);
}
static void ui_pathtextfield_clear(StackPanel& buttons) {
for (
int i = buttons.Children().Size() -
1; i >=
0; i--) {
buttons.Children().RemoveAt(i);
}
}
static void ui_pathfield_free_pathelms(UiPathElm* elms,
size_t nelm) {
if (!elms) {
return;
}
for (
int i =
0; i < nelm; i++) {
UiPathElm e = elms[i];
free(e.name);
free(e.path);
}
free(elms);
}
UiPathTextField::~UiPathTextField() {
ui_pathfield_free_pathelms(this->current_path, this->current_path_nelms);
}
static UiPathElm* default_pathelm_func(
const char* full_path,
size_t len,
size_t* ret_nelm,
void* data) {
cxstring *pathelms;
size_t nelm = cx_strsplit_a(cxDefaultAllocator, cx_strn(full_path, len),
CX_STR(
"/"),
4096, &pathelms);
if (nelm ==
0) {
*ret_nelm =
0;
return nullptr;
}
UiPathElm* elms = (UiPathElm*)calloc(nelm,
sizeof(UiPathElm));
size_t n = nelm;
int j =
0;
for (
int i =
0; i < nelm; i++) {
cxstring c = pathelms[i];
if (c.length ==
0) {
if (i ==
0) {
c.length =
1;
}
else {
n--;
continue;
}
}
cxmutstr m = cx_strdup(c);
elms[j].name = m.ptr;
elms[j].name_len = m.length;
size_t elm_path_len = c.ptr + c.length - full_path;
cxmutstr elm_path = cx_strdup(cx_strn(full_path, elm_path_len));
elms[j].path = elm_path.ptr;
elms[j].path_len = elm_path.length;
j++;
}
*ret_nelm = n;
return elms;
}
int ui_pathtextfield_update(UiPathTextField* pb,
const char *full_path) {
Grid grid = pb->grid;
ui_pathelm_func getpathelm = pb->getpathelm;
void* getpathelmdata = pb->getpathelmdata;
size_t full_path_len = full_path ? strlen(full_path) :
0;
size_t nelm =
0;
UiPathElm* path_elm = getpathelm(full_path, full_path_len, &nelm, getpathelmdata);
if (!path_elm) {
return 1;
}
pb->textbox.Visibility(Visibility::Collapsed);
pb->buttons.Visibility(Visibility::Visible);
ui_pathtextfield_clear(pb->buttons);
ui_pathfield_free_pathelms(pb->current_path, pb->current_path_nelms);
pb->current_path = path_elm;
pb->current_path_nelms = nelm;
int j =
0;
for (
int i =
0; i < nelm;i++) {
UiPathElm elm = path_elm[i];
wchar_t* wstr = str2wstr_len(elm.name, elm.name_len, nullptr);
Button button = Button();
button.Content(box_value(wstr));
free(wstr);
if (pb->onactivate) {
button.Click([pb, j, elm](IInspectable
const& sender, RoutedEventArgs) {
cxmutstr elmpath = cx_strdup(cx_strn(elm.path, elm.path_len));
UiEvent evt;
evt.obj = pb->obj;
evt.window = evt.obj->window;
evt.document = evt.obj->ctx->document;
evt.eventdata = elmpath.ptr;
evt.intval = j;
pb->onactivate(&evt, pb->onactivatedata);
free(elmpath.ptr);
});
}
Thickness t = {
0,
0,
1,
0 };
CornerRadius c = {
0 ,
0,
0,
0 };
button.BorderThickness(t);
button.CornerRadius(c);
pb->buttons.Children().Append(button);
j++;
}
return 0;
}
char* ui_path_textfield_get(UiString * str) {
UiPathTextField* widget = (UiPathTextField*)str->obj;
TextBox box = widget->textbox;
std::wstring wstr(box.Text());
return ui_wstring_get(str, wstr);
}
void ui_path_textfield_set(UiString* str,
const char* newvalue) {
UiPathTextField* widget = (UiPathTextField*)str->obj;
TextBox box = widget->textbox;
box.Text(ui_wstring_set(str, newvalue));
ui_pathtextfield_update(widget, newvalue);
}
UIEXPORT UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) {
UiObject* current = uic_current_obj(obj);
Border pathbar = Border();
IInspectable bgRes = Application::Current().Resources().Lookup(box_value(
"TextControlBackground"L));
IInspectable borderThicknessRes = Application::Current().Resources().Lookup(box_value(
"TextControlBorderThemeThickness"L));
IInspectable borderBrushRes = Application::Current().Resources().Lookup(box_value(
"TextControlBorderBrush"L));
Brush bgBrush = unbox_value<Brush>(bgRes);
Thickness border = unbox_value<Thickness>(borderThicknessRes);
Brush borderBrush = unbox_value<Brush>(borderBrushRes);
CornerRadius cornerRadius = {
4,
4,
4,
4 };
pathbar.Background(bgBrush);
pathbar.BorderBrush(borderBrush);
pathbar.BorderThickness(border);
pathbar.CornerRadius(cornerRadius);
Grid content = Grid();
pathbar.Child(content);
GridLength gl;
gl.Value =
0;
gl.GridUnitType = GridUnitType::Auto;
ColumnDefinition coldef = ColumnDefinition();
coldef.Width(gl);
content.ColumnDefinitions().Append(coldef);
gl.Value =
1;
gl.GridUnitType = GridUnitType::Star;
ColumnDefinition coldef2 = ColumnDefinition();
coldef2.Width(gl);
content.ColumnDefinitions().Append(coldef2);
TextBox pathTextBox = TextBox();
Thickness t = {
0,
0,
0,
0 };
CornerRadius c = {
0 ,
0,
0,
0 };
pathTextBox.BorderThickness(t);
pathTextBox.HorizontalAlignment(HorizontalAlignment::Stretch);
content.SetColumn(pathTextBox,
0);
content.SetColumnSpan(pathTextBox,
2);
content.Children().Append(pathTextBox);
StackPanel buttons = StackPanel();
buttons.Orientation(Orientation::Horizontal);
buttons.Visibility(Visibility::Collapsed);
content.SetColumn(buttons,
0);
content.Children().Append(buttons);
TextBlock filler = TextBlock();
filler.VerticalAlignment(VerticalAlignment::Stretch);
filler.HorizontalAlignment(HorizontalAlignment::Stretch);
filler.VerticalAlignment(VerticalAlignment::Stretch);
content.SetColumn(filler,
1);
content.Children().Append(filler);
filler.PointerPressed(
winrt::Microsoft::
UI::Xaml::Input::PointerEventHandler(
[=](IInspectable
const& sender, winrt::Microsoft::
UI::Xaml::Input::PointerRoutedEventArgs
const& args) {
pathTextBox.Visibility(Visibility::Visible);
buttons.Visibility(Visibility::Collapsed);
filler.Visibility(Visibility::Collapsed);
pathTextBox.SelectionStart(pathTextBox.Text().size());
pathTextBox.SelectionLength(
0);
pathTextBox.Focus(FocusState::Keyboard);
})
);
UiPathTextField* uipathbar = new UiPathTextField;
ui_context_add_pathtextfield_destructor(current->ctx, uipathbar);
uipathbar->grid = content;
uipathbar->buttons = buttons;
uipathbar->textbox = pathTextBox;
uipathbar->filler = filler;
uipathbar->obj = obj;
uipathbar->getpathelm = args.getpathelm ? args.getpathelm : default_pathelm_func;
uipathbar->getpathelmdata = args.getpathelmdata;
uipathbar->onactivate = args.onactivate;
uipathbar->onactivatedata = args.onactivatedata;
uipathbar->ondragstart = args.ondragstart;
uipathbar->ondragstartdata = args.ondragstartdata;
uipathbar->ondragcomplete = args.ondragcomplete;
uipathbar->ondragcompletedata = args.ondragcompletedata;
uipathbar->ondrop = args.ondrop;
uipathbar->ondropdata = args.ondropsdata;
pathTextBox.KeyDown(
winrt::Microsoft::
UI::Xaml::Input::KeyEventHandler(
[=](winrt::Windows::Foundation::IInspectable
const& sender, winrt::Microsoft::
UI::Xaml::Input::KeyRoutedEventArgs
const& e) {
auto key = e.Key();
bool showButtons = false;
bool update = false;
if (key == Windows::System::VirtualKey::Escape) {
showButtons = true;
}
else if (key == Windows::System::VirtualKey::Enter) {
showButtons = true;
update = true;
}
if (showButtons) {
pathTextBox.Visibility(Visibility::Collapsed);
buttons.Visibility(Visibility::Visible);
filler.Visibility(Visibility::Visible);
if (update) {
std::wstring value(pathTextBox.Text());
char* full_path = wchar2utf8(value.c_str(), value.length());
if (!ui_pathtextfield_update(uipathbar, full_path)) {
UiEvent evt;
evt.obj = obj;
evt.window = obj->window;
evt.document = obj->ctx->document;
evt.eventdata = full_path;
evt.intval = -
1;
args.onactivate(&evt, args.onactivatedata);
}
free(full_path);
}
}
})
);
UIElement elm = pathbar;
UiWidget* widget = new UiWidget(elm);
widget->data1 = uipathbar;
ui_context_add_widget_destructor(current->ctx, widget);
UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname,
UI_VAR_STRING);
if (var) {
UiString* value = (UiString*)var->value;
value->obj = uipathbar;
value->get = ui_path_textfield_get;
value->set = ui_path_textfield_set;
}
UI_APPLY_LAYOUT1(current, args);
current->container->Add(pathbar, false);
return widget;
}