summaryrefslogtreecommitdiff
path: root/src/ios.m
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-12-05 07:54:15 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-12-05 07:54:15 +0200
commitb8656d5a2e0f540d47d2dc5ccc269f709dd0b923 (patch)
treefbfc90bddc79bf35fb024293270f71496186fb22 /src/ios.m
parent8050511b683d89c5ef907bc461b98e9aaaa051a7 (diff)
iOS: Multiline text input using UITextView
Diffstat (limited to 'src/ios.m')
-rw-r--r--src/ios.m158
1 files changed, 126 insertions, 32 deletions
diff --git a/src/ios.m b/src/ios.m
index 59d02fc4..02659c55 100644
--- a/src/ios.m
+++ b/src/ios.m
@@ -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
280replacementString:(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
288static void enableMouse_(iBool yes) { 293static void enableMouse_(iBool yes) {
@@ -538,6 +543,10 @@ void init_AVFAudioPlayer(iAVFAudioPlayer *d) {
538 543
539void deinit_AVFAudioPlayer(iAVFAudioPlayer *d) { 544void 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
543static const char *cacheDir_ = "~/Library/Caches/Audio"; 552static const char *cacheDir_ = "~/Library/Caches/Audio";
@@ -638,70 +647,155 @@ iBool isPaused_AVFAudioPlayer(const iAVFAudioPlayer *d) {
638/*----------------------------------------------------------------------------------------------*/ 647/*----------------------------------------------------------------------------------------------*/
639 648
640struct Impl_SystemTextInput { 649struct 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
646iDefineTypeConstructionArgs(SystemTextInput, (int flags), flags) 657iDefineTypeConstructionArgs(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
650void init_SystemTextInput(iSystemTextInput *d, int flags) { 662static 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
673static 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
681void 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
676void deinit_SystemTextInput(iSystemTextInput *d) { 732void 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
682void setText_SystemTextInput(iSystemTextInput *d, const iString *text) { 746void 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
762int 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
687void setFont_SystemTextInput(iSystemTextInput *d, int fontId) { 770void 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
693const iString *text_SystemTextInput(const iSystemTextInput *d) { 781const 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
697void setRect_SystemTextInput(iSystemTextInput *d, iRect rect) { 791void 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
707void setTextChangedFunc_SystemTextInput(iSystemTextInput *d, 801void setTextChangedFunc_SystemTextInput(iSystemTextInput *d,