The Battle for Wesnoth  1.19.22+dev
apple_video.mm
Go to the documentation of this file.
1 /*
2  Copyright (C) 2020 - 2025
3  by Martin HrubĂ˝ <hrubymar10@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #ifdef __APPLE__
17 #include <TargetConditionals.h>
18 #if TARGET_OS_OSX
19 
20 #include "apple_video.hpp"
21 
22 #import <AppKit/AppKit.h>
23 #import <Foundation/Foundation.h>
24 
25 namespace desktop {
26 namespace apple {
27  CGFloat get_scale_factor(int display_index) {
28  CGFloat scale_factor = 1.0f;
29 
30  NSArray *screens = [NSScreen screens];
31 
32  if ([screens[display_index] respondsToSelector:@selector(backingScaleFactor)]) { // Mac OS X 10.7 and later
33  scale_factor = [screens[display_index] backingScaleFactor];
34  }
35 
36  return scale_factor;
37  }
38 
40  {
41  // iOS-only, no-op on macOS.
42  }
43 } // end namespace apple
44 } // end namespace desktop
45 
46 #elif TARGET_OS_IOS
47 
48 #include "apple_video.hpp"
49 
50 #include <SDL2/SDL_keyboard.h>
51 
52 #import <UIKit/UIKit.h>
53 
54 static __weak UIResponder* first_responder = nil;
55 
56 @interface UIResponder (WesnothFirstResponderCapture)
57 - (void)wesnoth_capture_first_responder:(id)sender;
58 @end
59 
60 @implementation UIResponder (WesnothFirstResponderCapture)
61 - (void)wesnoth_capture_first_responder:(id)sender
62 {
63  (void)sender;
64  first_responder = self;
65 }
66 @end
67 
68 @interface wesnoth_keyboard_toolbar : NSObject
69 + (instancetype)shared;
70 - (void)attach_toolbar_to_first_responder;
71 @end
72 
73 @implementation wesnoth_keyboard_toolbar
74 
75 + (instancetype)shared
76 {
77  static wesnoth_keyboard_toolbar* instance = nil;
78  static dispatch_once_t once_token;
79  dispatch_once(&once_token, ^{
80  instance = [[wesnoth_keyboard_toolbar alloc] init];
81  });
82  return instance;
83 }
84 
85 - (instancetype)init
86 {
87  self = [super init];
88  if(self) {
89  [[NSNotificationCenter defaultCenter]
90  addObserver:self
91  selector:@selector(on_keyboard_will_show:)
92  name:UIKeyboardWillShowNotification
93  object:nil];
94  }
95  return self;
96 }
97 
98 - (UIResponder*)current_first_responder
99 {
100  first_responder = nil;
101  [[UIApplication sharedApplication]
102  sendAction:@selector(wesnoth_capture_first_responder:)
103  to:nil
104  from:nil
105  forEvent:nil];
106  return first_responder;
107 }
108 
109 - (UIToolbar*)dismiss_toolbar
110 {
111  static UIToolbar* toolbar = nil;
112  if(!toolbar) {
113  toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 44.0)];
114  UIBarButtonItem* flex = [[UIBarButtonItem alloc]
115  initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
116  target:nil
117  action:nil];
118  UIBarButtonItem* dismiss = [[UIBarButtonItem alloc]
119  initWithTitle:NSLocalizedString(@"Dismiss", @"Dismiss keyboard button")
120  style:UIBarButtonItemStyleDone
121  target:self
122  action:@selector(on_dismiss_keyboard:)];
123  [toolbar setItems:@[flex, dismiss]];
124  [toolbar sizeToFit];
125  }
126  return toolbar;
127 }
128 
129 - (void)on_keyboard_will_show:(NSNotification*)notification
130 {
131  (void)notification;
132  [self attach_toolbar_to_first_responder];
133 }
134 
135 - (void)attach_toolbar_to_first_responder
136 {
137  UIResponder* responder = [self current_first_responder];
138  if([responder isKindOfClass:[UITextField class]]) {
139  UITextField* text_field = (UITextField*)responder;
140  UIToolbar* toolbar = [self dismiss_toolbar];
141  if(text_field.inputAccessoryView != toolbar) {
142  text_field.inputAccessoryView = toolbar;
143  [text_field reloadInputViews];
144  }
145  } else if([responder isKindOfClass:[UITextView class]]) {
146  UITextView* text_view = (UITextView*)responder;
147  UIToolbar* toolbar = [self dismiss_toolbar];
148  if(text_view.inputAccessoryView != toolbar) {
149  text_view.inputAccessoryView = toolbar;
150  [text_view reloadInputViews];
151  }
152  }
153 }
154 
155 - (void)on_dismiss_keyboard:(id)sender
156 {
157  (void)sender;
158  SDL_StopTextInput();
159 }
160 
161 @end
162 
163 namespace desktop {
164 namespace apple {
165  CGFloat get_scale_factor(int display_index) {
166  NSArray<UIScreen*>* screens = [UIScreen screens];
167  if(display_index >= 0 && static_cast<NSUInteger>(display_index) < screens.count) {
168  return screens[display_index].scale;
169  }
170  return UIScreen.mainScreen.scale;
171  }
172 
174  {
175  if([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
176  [wesnoth_keyboard_toolbar shared];
177  }
178  }
179 } // end namespace apple
180 } // end namespace desktop
181 
182 #endif //end TARGET_OS_OSX / TARGET_OS_IOS
183 #endif //end __APPLE__
void install_keyboard_dismiss_toolbar()
CGFloat get_scale_factor(int display_index)
struct utils::detail::formula_initer init