diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ios.h | 14 | ||||
-rw-r--r-- | src/ios.m | 158 | ||||
-rw-r--r-- | src/ui/inputwidget.c | 16 |
3 files changed, 148 insertions, 40 deletions
@@ -65,15 +65,16 @@ void updateNowPlayingInfo_iOS (void); | |||
65 | /*----------------------------------------------------------------------------------------------*/ | 65 | /*----------------------------------------------------------------------------------------------*/ |
66 | 66 | ||
67 | enum iSystemTextInputFlags { | 67 | enum iSystemTextInputFlags { |
68 | multiLine_SystemTextInputFlags = iBit(1), | 68 | selectAll_SystemTextInputFlags = iBit(1), |
69 | returnGo_SystemTextInputFlags = iBit(2), | 69 | multiLine_SystemTextInputFlags = iBit(2), |
70 | returnSend_SystemTextInputFlags = iBit(3), | 70 | returnGo_SystemTextInputFlags = iBit(3), |
71 | disableAutocorrect_SystemTextInputFlag = iBit(4), | 71 | returnSend_SystemTextInputFlags = iBit(4), |
72 | alignRight_SystemTextInputFlag = iBit(5), | 72 | disableAutocorrect_SystemTextInputFlag = iBit(5), |
73 | alignRight_SystemTextInputFlag = iBit(6), | ||
73 | }; | 74 | }; |
74 | 75 | ||
75 | iDeclareType(SystemTextInput) | 76 | iDeclareType(SystemTextInput) |
76 | iDeclareTypeConstructionArgs(SystemTextInput, int flags) | 77 | iDeclareTypeConstructionArgs(SystemTextInput, iRect rect, int flags) |
77 | 78 | ||
78 | void setRect_SystemTextInput (iSystemTextInput *, iRect rect); | 79 | void setRect_SystemTextInput (iSystemTextInput *, iRect rect); |
79 | void setText_SystemTextInput (iSystemTextInput *, const iString *text); | 80 | void setText_SystemTextInput (iSystemTextInput *, const iString *text); |
@@ -81,3 +82,4 @@ void setFont_SystemTextInput (iSystemTextInput *, int fontId); | |||
81 | void setTextChangedFunc_SystemTextInput (iSystemTextInput *, void (*textChangedFunc)(iSystemTextInput *, void *), void *); | 82 | void setTextChangedFunc_SystemTextInput (iSystemTextInput *, void (*textChangedFunc)(iSystemTextInput *, void *), void *); |
82 | 83 | ||
83 | const iString * text_SystemTextInput (const iSystemTextInput *); | 84 | const iString * text_SystemTextInput (const iSystemTextInput *); |
85 | int preferredHeight_SystemTextInput (const iSystemTextInput *); | ||
@@ -161,7 +161,7 @@ API_AVAILABLE(ios(13.0)) | |||
161 | 161 | ||
162 | /*----------------------------------------------------------------------------------------------*/ | 162 | /*----------------------------------------------------------------------------------------------*/ |
163 | 163 | ||
164 | @interface AppState : NSObject<UIDocumentPickerDelegate, UITextFieldDelegate> { | 164 | @interface AppState : NSObject<UIDocumentPickerDelegate, UITextFieldDelegate, UITextViewDelegate> { |
165 | iString *fileBeingSaved; | 165 | iString *fileBeingSaved; |
166 | iString *pickFileCommand; | 166 | iString *pickFileCommand; |
167 | iSystemTextInput *sysCtrl; | 167 | iSystemTextInput *sysCtrl; |
@@ -273,16 +273,21 @@ didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls { | |||
273 | SDL_Event ev = { .type = SDL_KEYDOWN }; | 273 | SDL_Event ev = { .type = SDL_KEYDOWN }; |
274 | ev.key.keysym.sym = SDLK_RETURN; | 274 | ev.key.keysym.sym = SDLK_RETURN; |
275 | SDL_PushEvent(&ev); | 275 | SDL_PushEvent(&ev); |
276 | printf("Return pressed\n"); | ||
277 | return NO; | 276 | return NO; |
278 | } | 277 | } |
279 | 278 | ||
280 | - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { | 279 | - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range |
280 | replacementString:(NSString *)string { | ||
281 | iSystemTextInput *sysCtrl = [appState_ systemTextInput]; | 281 | iSystemTextInput *sysCtrl = [appState_ systemTextInput]; |
282 | notifyChange_SystemTextInput_(sysCtrl); | 282 | notifyChange_SystemTextInput_(sysCtrl); |
283 | return YES; | 283 | return YES; |
284 | } | 284 | } |
285 | 285 | ||
286 | - (void)textViewDidChange:(UITextView *)textView { | ||
287 | iSystemTextInput *sysCtrl = [appState_ systemTextInput]; | ||
288 | notifyChange_SystemTextInput_(sysCtrl); | ||
289 | } | ||
290 | |||
286 | @end | 291 | @end |
287 | 292 | ||
288 | static void enableMouse_(iBool yes) { | 293 | static void enableMouse_(iBool yes) { |
@@ -538,6 +543,10 @@ void init_AVFAudioPlayer(iAVFAudioPlayer *d) { | |||
538 | 543 | ||
539 | void deinit_AVFAudioPlayer(iAVFAudioPlayer *d) { | 544 | void deinit_AVFAudioPlayer(iAVFAudioPlayer *d) { |
540 | setInput_AVFAudioPlayer(d, NULL, NULL); | 545 | setInput_AVFAudioPlayer(d, NULL, NULL); |
546 | if (d->player) { | ||
547 | CFBridgingRelease(d->player); | ||
548 | d->player = nil; | ||
549 | } | ||
541 | } | 550 | } |
542 | 551 | ||
543 | static const char *cacheDir_ = "~/Library/Caches/Audio"; | 552 | static const char *cacheDir_ = "~/Library/Caches/Audio"; |
@@ -638,70 +647,155 @@ iBool isPaused_AVFAudioPlayer(const iAVFAudioPlayer *d) { | |||
638 | /*----------------------------------------------------------------------------------------------*/ | 647 | /*----------------------------------------------------------------------------------------------*/ |
639 | 648 | ||
640 | struct Impl_SystemTextInput { | 649 | struct Impl_SystemTextInput { |
641 | void *ctrl; | 650 | int flags; |
651 | void *field; /* single-line text field */ | ||
652 | void *view; /* multi-line text view */ | ||
642 | void (*textChangedFunc)(iSystemTextInput *, void *); | 653 | void (*textChangedFunc)(iSystemTextInput *, void *); |
643 | void *textChangedContext; | 654 | void *textChangedContext; |
644 | }; | 655 | }; |
645 | 656 | ||
646 | iDefineTypeConstructionArgs(SystemTextInput, (int flags), flags) | 657 | iDefineTypeConstructionArgs(SystemTextInput, (iRect rect, int flags), rect, flags) |
647 | 658 | ||
648 | #define REF_d_ctrl (__bridge UITextField *)d->ctrl | 659 | #define REF_d_field (__bridge UITextField *)d->field |
660 | #define REF_d_view (__bridge UITextView *)d->view | ||
649 | 661 | ||
650 | void init_SystemTextInput(iSystemTextInput *d, int flags) { | 662 | static CGRect convertToCGRect_(const iRect *rect) { |
651 | d->ctrl = (void *) CFBridgingRetain([[UITextField alloc] init]); | 663 | const iWindow *win = get_Window(); |
652 | UITextField *field = REF_d_ctrl; | 664 | CGRect frame; |
665 | // TODO: Convert coordinates properly! | ||
666 | frame.origin.x = rect->pos.x / win->pixelRatio; | ||
667 | frame.origin.y = (rect->pos.y - gap_UI + 2) / win->pixelRatio; | ||
668 | frame.size.width = rect->size.x / win->pixelRatio; | ||
669 | frame.size.height = rect->size.y / win->pixelRatio; | ||
670 | return frame; | ||
671 | } | ||
672 | |||
673 | static UIColor *makeUIColor_(enum iColorId colorId) { | ||
674 | iColor color = get_Color(colorId); | ||
675 | return [UIColor colorWithRed:color.r / 255.0 | ||
676 | green:color.g / 255.0 | ||
677 | blue:color.b / 255.0 | ||
678 | alpha:color.a / 255.0]; | ||
679 | } | ||
680 | |||
681 | void init_SystemTextInput(iSystemTextInput *d, iRect rect, int flags) { | ||
682 | d->flags = flags; | ||
683 | d->field = NULL; | ||
684 | d->view = NULL; | ||
685 | CGRect frame = convertToCGRect_(&rect); | ||
686 | if (flags & multiLine_SystemTextInputFlags) { | ||
687 | d->view = (void *) CFBridgingRetain([[UITextView alloc] initWithFrame:frame textContainer:nil]); | ||
688 | [[viewController_(get_Window()) view] addSubview:REF_d_view]; | ||
689 | } | ||
690 | else { | ||
691 | d->field = (void *) CFBridgingRetain([[UITextField alloc] initWithFrame:frame]); | ||
692 | [[viewController_(get_Window()) view] addSubview:REF_d_field]; | ||
693 | } | ||
694 | UIControl<UITextInputTraits> *traits = (UIControl<UITextInputTraits> *) (d->view ? REF_d_view : REF_d_field); | ||
653 | // TODO: Use the right font: https://developer.apple.com/documentation/uikit/text_display_and_fonts/adding_a_custom_font_to_your_app?language=objc | 695 | // TODO: Use the right font: https://developer.apple.com/documentation/uikit/text_display_and_fonts/adding_a_custom_font_to_your_app?language=objc |
654 | [[viewController_(get_Window()) view] addSubview:REF_d_ctrl]; | ||
655 | if (flags & returnGo_SystemTextInputFlags) { | 696 | if (flags & returnGo_SystemTextInputFlags) { |
656 | [field setReturnKeyType:UIReturnKeyGo]; | 697 | [traits setReturnKeyType:UIReturnKeyGo]; |
657 | } | 698 | } |
658 | if (flags & returnSend_SystemTextInputFlags) { | 699 | if (flags & returnSend_SystemTextInputFlags) { |
659 | [field setReturnKeyType:UIReturnKeySend]; | 700 | [traits setReturnKeyType:UIReturnKeySend]; |
660 | } | 701 | } |
661 | if (flags & disableAutocorrect_SystemTextInputFlag) { | 702 | if (flags & disableAutocorrect_SystemTextInputFlag) { |
662 | [field setAutocorrectionType:UITextAutocorrectionTypeNo]; | 703 | [traits setAutocorrectionType:UITextAutocorrectionTypeNo]; |
663 | [field setAutocapitalizationType:UITextAutocapitalizationTypeNone]; | 704 | [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone]; |
664 | [field setSpellCheckingType:UITextSpellCheckingTypeNo]; | 705 | [traits setSpellCheckingType:UITextSpellCheckingTypeNo]; |
665 | } | 706 | } |
666 | if (flags & alignRight_SystemTextInputFlag) { | 707 | if (flags & alignRight_SystemTextInputFlag) { |
667 | [field setTextAlignment:NSTextAlignmentRight]; | 708 | if (d->field) { |
709 | [REF_d_field setTextAlignment:NSTextAlignmentRight]; | ||
710 | } | ||
711 | } | ||
712 | UIColor *textColor = makeUIColor_(uiInputTextFocused_ColorId); | ||
713 | UIColor *backgroundColor = makeUIColor_(uiInputBackgroundFocused_ColorId); | ||
714 | [appState_ setSystemTextInput:d]; | ||
715 | if (d->field) { | ||
716 | [REF_d_field setTextColor:textColor]; | ||
717 | [REF_d_field setDelegate:appState_]; | ||
718 | [REF_d_field becomeFirstResponder]; | ||
719 | } | ||
720 | else { | ||
721 | [REF_d_view setTextColor:textColor]; | ||
722 | [REF_d_view setBackgroundColor:backgroundColor]; | ||
723 | [REF_d_view setEditable:YES]; | ||
724 | // [REF_d_view setSelectable:YES]; | ||
725 | [REF_d_view setDelegate:appState_]; | ||
726 | [REF_d_view becomeFirstResponder]; | ||
668 | } | 727 | } |
669 | [field setDelegate:appState_]; | ||
670 | [field becomeFirstResponder]; | ||
671 | d->textChangedFunc = NULL; | 728 | d->textChangedFunc = NULL; |
672 | d->textChangedContext = NULL; | 729 | d->textChangedContext = NULL; |
673 | [appState_ setSystemTextInput:d]; | ||
674 | } | 730 | } |
675 | 731 | ||
676 | void deinit_SystemTextInput(iSystemTextInput *d) { | 732 | void deinit_SystemTextInput(iSystemTextInput *d) { |
677 | [appState_ setSystemTextInput:nil]; | 733 | [appState_ setSystemTextInput:nil]; |
678 | [REF_d_ctrl removeFromSuperview]; | 734 | if (d->field) { |
679 | d->ctrl = nil; // TODO: Does this need to be released?? | 735 | [REF_d_field removeFromSuperview]; |
736 | CFBridgingRelease(d->field); | ||
737 | d->field = nil; | ||
738 | } | ||
739 | if (d->view) { | ||
740 | [REF_d_view removeFromSuperview]; | ||
741 | CFBridgingRelease(d->view); | ||
742 | d->view = nil; | ||
743 | } | ||
680 | } | 744 | } |
681 | 745 | ||
682 | void setText_SystemTextInput(iSystemTextInput *d, const iString *text) { | 746 | void setText_SystemTextInput(iSystemTextInput *d, const iString *text) { |
683 | [REF_d_ctrl setText:[NSString stringWithUTF8String:cstr_String(text)]]; | 747 | NSString *str = [NSString stringWithUTF8String:cstr_String(text)]; |
684 | [REF_d_ctrl selectAll:nil]; | 748 | if (d->field) { |
749 | [REF_d_field setText:str]; | ||
750 | if (d->flags & selectAll_SystemTextInputFlags) { | ||
751 | [REF_d_field selectAll:nil]; | ||
752 | } | ||
753 | } | ||
754 | else { | ||
755 | [REF_d_view setText:str]; | ||
756 | if (d->flags & selectAll_SystemTextInputFlags) { | ||
757 | [REF_d_view selectAll:nil]; | ||
758 | } | ||
759 | } | ||
760 | } | ||
761 | |||
762 | int preferredHeight_SystemTextInput(const iSystemTextInput *d) { | ||
763 | if (d->view) { | ||
764 | CGRect usedRect = [[REF_d_view layoutManager] usedRectForTextContainer:[REF_d_view textContainer]]; | ||
765 | return usedRect.size.height * get_Window()->pixelRatio; | ||
766 | } | ||
767 | return 0; | ||
685 | } | 768 | } |
686 | 769 | ||
687 | void setFont_SystemTextInput(iSystemTextInput *d, int fontId) { | 770 | void setFont_SystemTextInput(iSystemTextInput *d, int fontId) { |
688 | int height = lineHeight_Text(fontId); | 771 | int height = lineHeight_Text(fontId); |
689 | UIFont *font = [UIFont systemFontOfSize:0.65f * height / get_Window()->pixelRatio]; | 772 | UIFont *font = [UIFont systemFontOfSize:0.65f * height / get_Window()->pixelRatio]; |
690 | [REF_d_ctrl setFont:font]; | 773 | if (d->field) { |
774 | [REF_d_field setFont:font]; | ||
775 | } | ||
776 | if (d->view) { | ||
777 | [REF_d_view setFont:font]; | ||
778 | } | ||
691 | } | 779 | } |
692 | 780 | ||
693 | const iString *text_SystemTextInput(const iSystemTextInput *d) { | 781 | const iString *text_SystemTextInput(const iSystemTextInput *d) { |
694 | return collectNewCStr_String([[REF_d_ctrl text] cStringUsingEncoding:NSUTF8StringEncoding]);; | 782 | if (d->field) { |
783 | return collectNewCStr_String([[REF_d_field text] cStringUsingEncoding:NSUTF8StringEncoding]); | ||
784 | } | ||
785 | if (d->view) { | ||
786 | return collectNewCStr_String([[REF_d_view text] cStringUsingEncoding:NSUTF8StringEncoding]); | ||
787 | } | ||
788 | return NULL; | ||
695 | } | 789 | } |
696 | 790 | ||
697 | void setRect_SystemTextInput(iSystemTextInput *d, iRect rect) { | 791 | void setRect_SystemTextInput(iSystemTextInput *d, iRect rect) { |
698 | const iWindow *win = get_Window(); | 792 | CGRect frame = convertToCGRect_(&rect); |
699 | CGRect frame; | 793 | if (d->field) { |
700 | frame.origin.x = rect.pos.x / win->pixelRatio; | 794 | [REF_d_field setFrame:frame]; |
701 | frame.origin.y = (rect.pos.y - gap_UI + 2) / win->pixelRatio; | 795 | } |
702 | frame.size.width = rect.size.x / win->pixelRatio; | 796 | else { |
703 | frame.size.height = rect.size.y / win->pixelRatio; | 797 | [REF_d_view setFrame:frame]; |
704 | [REF_d_ctrl setFrame:frame]; | 798 | } |
705 | } | 799 | } |
706 | 800 | ||
707 | void setTextChangedFunc_SystemTextInput(iSystemTextInput *d, | 801 | void setTextChangedFunc_SystemTextInput(iSystemTextInput *d, |
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index 1c6b8d9e..ea7ed523 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -596,10 +596,19 @@ static size_t length_InputWidget_(const iInputWidget *d) { | |||
596 | } | 596 | } |
597 | 597 | ||
598 | static int contentHeight_InputWidget_(const iInputWidget *d) { | 598 | static int contentHeight_InputWidget_(const iInputWidget *d) { |
599 | if (d->sysCtrl) { | ||
600 | const int preferred = preferredHeight_SystemTextInput(d->sysCtrl); | ||
601 | return iClamp(preferred, | ||
602 | d->minWrapLines * lineHeight_Text(d->font), | ||
603 | d->maxWrapLines * lineHeight_Text(d->font)); | ||
604 | } | ||
599 | return size_Range(&d->visWrapLines) * lineHeight_Text(d->font); | 605 | return size_Range(&d->visWrapLines) * lineHeight_Text(d->font); |
600 | } | 606 | } |
601 | 607 | ||
602 | static void updateTextInputRect_InputWidget_(const iInputWidget *d) { | 608 | static void updateTextInputRect_InputWidget_(const iInputWidget *d) { |
609 | if (d->sysCtrl) { | ||
610 | setRect_SystemTextInput(d->sysCtrl, contentBounds_InputWidget_(d)); | ||
611 | } | ||
603 | #if !defined (iPlatformAppleMobile) | 612 | #if !defined (iPlatformAppleMobile) |
604 | const iRect bounds = bounds_Widget(constAs_Widget(d)); | 613 | const iRect bounds = bounds_Widget(constAs_Widget(d)); |
605 | SDL_SetTextInputRect(&(SDL_Rect){ bounds.pos.x, bounds.pos.y, bounds.size.x, bounds.size.y }); | 614 | SDL_SetTextInputRect(&(SDL_Rect){ bounds.pos.x, bounds.pos.y, bounds.size.x, bounds.size.y }); |
@@ -1036,6 +1045,7 @@ void systemInputChanged_InputWidget_(iSystemTextInput *sysCtrl, void *widget) { | |||
1036 | iInputWidget *d = widget; | 1045 | iInputWidget *d = widget; |
1037 | splitToLines_(text_SystemTextInput(sysCtrl), &d->lines); | 1046 | splitToLines_(text_SystemTextInput(sysCtrl), &d->lines); |
1038 | contentsWereChanged_InputWidget_(d); | 1047 | contentsWereChanged_InputWidget_(d); |
1048 | updateMetrics_InputWidget_(d); | ||
1039 | } | 1049 | } |
1040 | #endif | 1050 | #endif |
1041 | 1051 | ||
@@ -1050,14 +1060,16 @@ void begin_InputWidget(iInputWidget *d) { | |||
1050 | setFlags_Widget(w, selected_WidgetFlag, iTrue); | 1060 | setFlags_Widget(w, selected_WidgetFlag, iTrue); |
1051 | mergeLines_(&d->lines, &d->oldText); | 1061 | mergeLines_(&d->lines, &d->oldText); |
1052 | #if defined (LAGRANGE_ENABLE_SYSTEM_INPUT) | 1062 | #if defined (LAGRANGE_ENABLE_SYSTEM_INPUT) |
1053 | d->sysCtrl = new_SystemTextInput((d->inFlags & isUrl_InputWidgetFlag ? disableAutocorrect_SystemTextInputFlag : 0) | | 1063 | d->sysCtrl = new_SystemTextInput(contentBounds_InputWidget_(d), |
1064 | (d->maxWrapLines > 1 ? multiLine_SystemTextInputFlags : 0) | | ||
1065 | (d->inFlags & isUrl_InputWidgetFlag ? disableAutocorrect_SystemTextInputFlag : 0) | | ||
1054 | (!cmp_String(id_Widget(w), "url") ? returnGo_SystemTextInputFlags : 0) | | 1066 | (!cmp_String(id_Widget(w), "url") ? returnGo_SystemTextInputFlags : 0) | |
1055 | (flags_Widget(w) & alignRight_WidgetFlag ? alignRight_SystemTextInputFlag : 0)); | 1067 | (flags_Widget(w) & alignRight_WidgetFlag ? alignRight_SystemTextInputFlag : 0)); |
1056 | setFont_SystemTextInput(d->sysCtrl, d->font); | 1068 | setFont_SystemTextInput(d->sysCtrl, d->font); |
1057 | setRect_SystemTextInput(d->sysCtrl, contentBounds_InputWidget_(d)); | ||
1058 | setText_SystemTextInput(d->sysCtrl, &d->oldText); | 1069 | setText_SystemTextInput(d->sysCtrl, &d->oldText); |
1059 | setTextChangedFunc_SystemTextInput(d->sysCtrl, systemInputChanged_InputWidget_, d); | 1070 | setTextChangedFunc_SystemTextInput(d->sysCtrl, systemInputChanged_InputWidget_, d); |
1060 | iConnect(Root, w->root, visualOffsetsChanged, d, updateAfterVisualOffsetChange_InputWidget_); | 1071 | iConnect(Root, w->root, visualOffsetsChanged, d, updateAfterVisualOffsetChange_InputWidget_); |
1072 | updateMetrics_InputWidget_(d); | ||
1061 | return; | 1073 | return; |
1062 | #endif | 1074 | #endif |
1063 | if (d->mode == overwrite_InputMode) { | 1075 | if (d->mode == overwrite_InputMode) { |