Feat[controls]: v3: joystick & conditonal visibility

- Finish joystick view
+ Finish forward lock
+ When in menu, oystick can be used to move the virtual mouse
- Finish conditonal visibility
- Replace Make Default with Load
This commit is contained in:
Duy Tran Khanh committed 2023-08-11 20:58:14 +07:00
1 parent 63261cf60a
commit 36c3e312f3
14 files changed
+517 -139

No files matched your search

+1
View File
@@ -112,6 +112,7 @@ add_executable(PojavLauncher
customcontrols/ControlButton.m
customcontrols/ControlDrawer.m
customcontrols/ControlJoystick.m
customcontrols/ControlLayout.m
customcontrols/ControlSubButton.m
customcontrols/CustomControlsUtils.m
@@ -1,5 +1,6 @@
#import "CustomControlsViewController.h"
#import "customcontrols/ControlDrawer.h"
#import "customcontrols/ControlJoystick.h"
#import "customcontrols/ControlLayout.h"
#import "utils.h"
@@ -8,7 +9,7 @@
- (void)doAddButton:(ControlButton *)button atIndex:(NSNumber *)index {
NSUndoManager *undo = self.undoManager;
if ([button isKindOfClass:[ControlSubButton class]]) {
if ([button isKindOfClass:ControlSubButton.class]) {
undo.actionName = localize(@"custom_controls.button_menu.add_subbutton", nil);
[self.ctrlView addSubview:button];
@@ -16,7 +17,7 @@
[drawer.buttons insertObject:button atIndex:index.intValue];
[drawer.drawerData[@"buttonProperties"] insertObject:button.properties atIndex:index.intValue];
[drawer syncButtons];
} else if ([button isKindOfClass:[ControlDrawer class]]) {
} else if ([button isKindOfClass:ControlDrawer.class]) {
undo.actionName = localize(@"custom_controls.control_menu.add_drawer", nil);
for (ControlSubButton *subButton in ((ControlDrawer *)button).buttons) {
@@ -24,6 +25,10 @@
}
[self.ctrlView.layoutDictionary[@"mDrawerDataList"] insertObject:((ControlDrawer *)button).drawerData atIndex:index.intValue];
[self.ctrlView addSubview:button];
} else if ([button isKindOfClass:ControlJoystick.class]) {
undo.actionName = localize(@"custom_controls.control_menu.add_joystick", nil);
[self.ctrlView.layoutDictionary[@"mJoystickDataList"] insertObject:button.properties atIndex:index.intValue];
[self.ctrlView addSubview:button];
} else {
undo.actionName = localize(@"custom_controls.control_menu.add_button", nil);
[self.ctrlView.layoutDictionary[@"mControlDataList"] insertObject:button.properties atIndex:index.intValue];
@@ -38,17 +43,20 @@
- (void)doRemoveButton:(ControlButton *)button {
NSNumber *index;
if ([button isKindOfClass:[ControlSubButton class]]) {
if ([button isKindOfClass:ControlSubButton.class]) {
ControlDrawer *parent = ((ControlSubButton *)button).parentDrawer;
index = @([parent.drawerData[@"buttonProperties"] indexOfObject:button.properties]);
[parent.buttons removeObject:button];
[parent.drawerData[@"buttonProperties"] removeObject:button.properties];
[parent syncButtons];
} else if ([button isKindOfClass:[ControlDrawer class]]) {
} else if ([button isKindOfClass:ControlDrawer.class]) {
ControlDrawer *drawer = (ControlDrawer *)button;
index = @([self.ctrlView.layoutDictionary[@"mDrawerDataList"] indexOfObject:drawer.drawerData]);
[drawer.buttons makeObjectsPerformSelector:@selector(removeFromSuperview)];
[self.ctrlView.layoutDictionary[@"mDrawerDataList"] removeObject:drawer.drawerData];
} else if ([button isKindOfClass:ControlJoystick.class]) {
index = @([self.ctrlView.layoutDictionary[@"mJoystickDataList"] indexOfObject:button.properties]);
[self.ctrlView.layoutDictionary[@"mJoystickDataList"] removeObject:button.properties];
} else {
index = @([self.ctrlView.layoutDictionary[@"mControlDataList"] indexOfObject:button.properties]);
[self.ctrlView.layoutDictionary[@"mControlDataList"] removeObject:button.properties];
+132 -75
View File
@@ -5,6 +5,7 @@
#import "ios_uikit_bridge.h"
#import "customcontrols/ControlDrawer.h"
#import "customcontrols/ControlJoystick.h"
#import "customcontrols/CustomControlsUtils.h"
#include <dlfcn.h>
@@ -235,11 +236,11 @@ BOOL shouldDismissPopover = YES;
UIMenuItem *actionExit = [[UIMenuItem alloc] initWithTitle:localize(@"custom_controls.control_menu.exit", nil) action:@selector(actionMenuExit)];
UIMenuItem *actionSave = [[UIMenuItem alloc] initWithTitle:localize(@"custom_controls.control_menu.save", nil) action:@selector(actionMenuSave)];
UIMenuItem *actionLoad = [[UIMenuItem alloc] initWithTitle:localize(@"custom_controls.control_menu.load", nil) action:@selector(actionMenuLoad)];
UIMenuItem *actionSetDef = [[UIMenuItem alloc] initWithTitle:localize(@"custom_controls.control_menu.make_default", nil) action:@selector(actionMenuSetDef)];
UIMenuItem *actionSafeArea = [[UIMenuItem alloc] initWithTitle:localize(@"custom_controls.control_menu.safe_area", nil) action:@selector(actionMenuSafeArea)];
UIMenuItem *actionAddButton = [[UIMenuItem alloc] initWithTitle:localize(@"custom_controls.control_menu.add_button", nil) action:@selector(actionMenuAddButton)];
UIMenuItem *actionAddDrawer = [[UIMenuItem alloc] initWithTitle:localize(@"custom_controls.control_menu.add_drawer", nil) action:@selector(actionMenuAddDrawer)];
[menuController setMenuItems:@[actionExit, actionSave, actionLoad, actionSetDef, actionSafeArea, actionAddButton, actionAddDrawer]];
UIMenuItem *actionAddJoystick = [[UIMenuItem alloc] initWithTitle:localize(@"custom_controls.control_menu.add_joystick", nil) action:@selector(actionMenuAddJoystick)];
[menuController setMenuItems:@[actionExit, actionSave, actionLoad, actionSafeArea, actionAddButton, actionAddDrawer, actionAddJoystick]];
CGPoint point = [sender locationInView:sender.view];
self.selectedPoint = CGRectMake(point.x, point.y, 1.0, 1.0);
@@ -334,13 +335,6 @@ BOOL shouldDismissPopover = YES;
}
- (void)actionMenuLoad {
[self actionOpenFilePicker:^void(NSString* name) {
self.currentFileName = name;
[self loadControlFile:[NSString stringWithFormat:@"%@.json", name]];
}];
}
- (void)actionMenuSetDef {
[self actionOpenFilePicker:^void(NSString* name) {
self.currentFileName = name;
name = [NSString stringWithFormat:@"%@.json", name];
@@ -377,10 +371,7 @@ BOOL shouldDismissPopover = YES;
- (void)actionMenuAddButtonWithDrawer:(ControlDrawer *)drawer {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
dict[@"name"] = @"New";
dict[@"keycodes"] = [[NSMutableArray alloc] initWithCapacity:4];
for (int i = 0; i < 4; i++) {
dict[@"keycodes"][i] = @(0);
}
dict[@"keycodes"] = @[@0, @0, @0, @0].mutableCopy;
dict[@"dynamicX"] = @"0";
dict[@"dynamicY"] = @"0";
dict[@"width"] = @(50.0);
@@ -390,6 +381,7 @@ BOOL shouldDismissPopover = YES;
dict[@"bgColor"] = @(0x4d000000);
ControlButton *button;
if (drawer == nil) {
dict[@"displayInGame"] = dict[@"displayInMenu"] = @YES;
button = [ControlButton buttonWithProperties:dict];
[self doAddButton:button atIndex:@([self.ctrlView.layoutDictionary[@"mControlDataList"] count])];
[button snapAndAlignX:self.selectedPoint.origin.x-25.0 Y:self.selectedPoint.origin.y-25.0];
@@ -423,6 +415,7 @@ BOOL shouldDismissPopover = YES;
properties[@"opacity"] = @(1);
properties[@"cornerRadius"] = @(0);
properties[@"bgColor"] = @(0x4d000000);
properties[@"displayInGame"] = properties[@"displayInMenu"] = @YES;
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
data[@"orientation"] = @"FREE";
data[@"properties"] = properties;
@@ -443,6 +436,26 @@ BOOL shouldDismissPopover = YES;
[self actionMenuAddButtonWithDrawer:(ControlDrawer *)self.currentGesture.view];
}
- (void)actionMenuAddJoystick {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
dict[@"dynamicX"] = @"0";
dict[@"dynamicY"] = @"0";
dict[@"width"] = @(100.0);
dict[@"height"] = @(100.0);
dict[@"opacity"] = @(1);
dict[@"bgColor"] = @(0x4d000000);
dict[@"displayInGame"] = dict[@"displayInMenu"] = @YES;
dict[@"forwardLock"] = @NO;
ControlJoystick *button = [ControlJoystick buttonWithProperties:dict];
[self doAddButton:button atIndex:@([self.ctrlView.layoutDictionary[@"mJoystickDataList"] count])];
[button snapAndAlignX:self.selectedPoint.origin.x-25.0 Y:self.selectedPoint.origin.y-25.0];
[button update];
[button addGestureRecognizer:[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(showControlPopover:)]];
[button addGestureRecognizer:[[UIPanGestureRecognizer alloc]
initWithTarget:self action:@selector(onTouch:)]];
}
- (void)actionMenuBtnCopy {
// copy
}
@@ -605,6 +618,10 @@ BOOL shouldDismissPopover = YES;
#define TAG_SLIDER_OPACITY 12
#define TAG_SWITCH_DYNAMICPOS 13
#define VISIBILITY_ALWAYS 0
#define VISIBILITY_IN_GAME 1
#define VISIBILITY_IN_MENU 2
#pragma mark - CCMenuViewController
CGFloat currentY;
@@ -613,7 +630,7 @@ CGFloat currentY;
}
@property(nonatomic) NSMutableArray *keyCodeMap, *keyValueMap;
@property(nonatomic) NSArray* arrOrientation;
@property(nonatomic) NSArray *arrOrientation, *arrVisibility;
@property(nonatomic) NSMutableDictionary* oldProperties;
@property UITextField *activeField;
@@ -621,8 +638,8 @@ CGFloat currentY;
@property(nonatomic) UITextField *editName, *editSizeWidth, *editSizeHeight;
@property(nonatomic) UITextView* editMapping;
@property(nonatomic) UIPickerView* pickerMapping;
@property(nonatomic) UISegmentedControl* ctrlOrientation;
@property(nonatomic) UISwitch *switchToggleable, *switchMousePass, *switchSwipeable;
@property(nonatomic) UISegmentedControl *ctrlOrientation, *ctrlVisibility;
@property(nonatomic) UISwitch *switchFwdLock, *switchToggleable, *switchMousePass, *switchSwipeable;
@property(nonatomic) UIColorWell *colorWellINTBackground, *colorWellINTStroke;
@property(nonatomic) DBNumberedSlider *sliderStrokeWidth, *sliderCornerRadius, *sliderOpacity;
@@ -692,18 +709,21 @@ CGFloat currentY;
// Property: Name
UILabel *labelName = [self addLabel:localize(@"custom_controls.button_edit.name", nil)];
self.editName = [[UITextField alloc] initWithFrame:CGRectMake(labelName.frame.size.width + 5.0, currentY, width - labelName.frame.size.width - 5.0, labelName.frame.size.height)];
[self.editName addTarget:self action:@selector(textFieldEditingChanged) forControlEvents:UIControlEventEditingChanged];
[self.editName addTarget:self.editName action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
self.editName.placeholder = localize(@"custom_controls.button_edit.name", nil);
self.editName.returnKeyType = UIReturnKeyDone;
self.editName.text = self.targetButton.properties[@"name"];
[self.scrollView addSubview:self.editName];
if (![self.targetButton isKindOfClass:ControlJoystick.class]) {
UILabel *labelName = [self addLabel:localize(@"custom_controls.button_edit.name", nil)];
self.editName = [[UITextField alloc] initWithFrame:CGRectMake(labelName.frame.size.width + 5.0, currentY, width - labelName.frame.size.width - 5.0, labelName.frame.size.height)];
[self.editName addTarget:self action:@selector(textFieldEditingChanged) forControlEvents:UIControlEventEditingChanged];
[self.editName addTarget:self.editName action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
self.editName.placeholder = localize(@"custom_controls.button_edit.name", nil);
self.editName.returnKeyType = UIReturnKeyDone;
self.editName.text = self.targetButton.properties[@"name"];
[self.scrollView addSubview:self.editName];
currentY += labelName.frame.size.height + 15.0;
}
if (![self.targetButton isKindOfClass:[ControlSubButton class]]) {
if (![self.targetButton isKindOfClass:ControlSubButton.class] ||
[((ControlSubButton *)self.targetButton).parentDrawer.drawerData[@"orientation"] isEqualToString:@"FREE"]) {
// Property: Size
currentY += labelName.frame.size.height + 12.0;
UILabel *labelSize = [self addLabel:localize(@"custom_controls.button_edit.size", nil)];
// width / 2.0 + (labelSize.frame.size.width + 4.0) / 2.0
CGFloat editSizeWidthValue = (width - labelSize.frame.size.width) / 2 - labelSize.frame.size.height / 2;
@@ -728,11 +748,29 @@ CGFloat currentY;
self.editSizeHeight.text = [self.targetButton.properties[@"height"] stringValue];
self.editSizeHeight.textAlignment = NSTextAlignmentCenter;
[self.scrollView addSubview:self.editSizeHeight];
currentY += labelSize.frame.size.height + 15.0;
}
currentY += labelName.frame.size.height + 12.0;
if (![self.targetButton isKindOfClass:[ControlDrawer class]]) {
if ([self.targetButton isKindOfClass:ControlDrawer.class]) {
// Property: Orientation
self.arrOrientation = @[@"DOWN", @"LEFT", @"UP", @"RIGHT", @"FREE"];
UILabel *labelOrientation = [self addLabel:localize(@"custom_controls.button_edit.orientation", nil)];
self.ctrlOrientation = [[UISegmentedControl alloc] initWithItems:self.arrOrientation];
[self.ctrlOrientation addTarget:self action:@selector(orientationValueChanged:) forControlEvents:UIControlEventValueChanged];
self.ctrlOrientation.frame = CGRectMake(labelOrientation.frame.size.width + 5.0, currentY - 5.0, width - labelOrientation.frame.size.width - 5.0, 30.0);
self.ctrlOrientation.selectedSegmentIndex = [self.arrOrientation indexOfObject:
((ControlDrawer *)self.targetButton).drawerData[@"orientation"]];
[self.scrollView addSubview:self.ctrlOrientation];
currentY += labelOrientation.frame.size.height + 15.0;
} else if ([self.targetButton isKindOfClass:ControlJoystick.class]) {
// Property: Forward lock
UILabel *labelFwdLock = [self addLabel:localize(@"custom_controls.button_edit.forward_lock", nil)];
self.switchFwdLock = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currentY - 5.0, 50.0, 30)];
[self.switchFwdLock setOn:[self.targetButton.properties[@"forwardLock"] boolValue] animated:NO];
[self.scrollView addSubview:self.switchFwdLock];
currentY += labelFwdLock.frame.size.height + 15.0;
} else {
// Property: Mapping
UILabel *labelMapping = [self addLabel:localize(@"custom_controls.button_edit.mapping", nil)];
@@ -754,87 +792,80 @@ CGFloat currentY;
self.editMapping.inputAccessoryView = editPickToolbar;
self.editMapping.inputView = self.pickerMapping;
[self.scrollView addSubview:self.editMapping];
currentY += self.editMapping.frame.size.height + 12.0;
} else {
// Property: Orientation
self.arrOrientation = @[@"DOWN", @"LEFT", @"UP", @"RIGHT", @"FREE"];
UILabel *labelOrientation = [self addLabel:localize(@"custom_controls.button_edit.orientation", nil)];
self.ctrlOrientation = [[UISegmentedControl alloc] initWithItems:self.arrOrientation];
[self.ctrlOrientation addTarget:self action:@selector(orientationValueChanged) forControlEvents:UIControlEventValueChanged];
self.ctrlOrientation.frame = CGRectMake(labelOrientation.frame.size.width + 5.0, currentY - 5.0, width - labelOrientation.frame.size.width - 5.0, 30.0);
self.ctrlOrientation.selectedSegmentIndex = [self.arrOrientation indexOfObject:
((ControlDrawer *)self.targetButton).drawerData[@"orientation"]];
[self.scrollView addSubview:self.ctrlOrientation];
currentY += labelName.frame.size.height + 12.0;
currentY += self.editMapping.frame.size.height + 15.0;
}
// Property: Toggleable
UILabel *labelToggleable = [self addLabel:localize(@"custom_controls.button_edit.toggleable", nil)];
self.switchToggleable = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currentY - 5.0, 50.0, 30)];
[self.switchToggleable setOn:[self.targetButton.properties[@"isToggle"] boolValue] animated:NO];
[self.scrollView addSubview:self.switchToggleable];
if (![self.targetButton isKindOfClass:ControlJoystick.class]) {
// Property: Toggleable
UILabel *labelToggleable = [self addLabel:localize(@"custom_controls.button_edit.toggleable", nil)];
self.switchToggleable = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currentY - 5.0, 50.0, 30)];
[self.switchToggleable setOn:[self.targetButton.properties[@"isToggle"] boolValue] animated:NO];
[self.scrollView addSubview:self.switchToggleable];
currentY += labelToggleable.frame.size.height + 15.0;
// Property: Mouse pass
currentY += labelName.frame.size.height + 12.0;
UILabel *labelMousePass = [self addLabel:localize(@"custom_controls.button_edit.mouse_pass", nil)];
self.switchMousePass = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currentY - 5.0, 50.0, 30)];
[self.switchMousePass setOn:[self.targetButton.properties[@"passThruEnabled"] boolValue]];
[self.scrollView addSubview:self.switchMousePass];
// Property: Mouse pass
UILabel *labelMousePass = [self addLabel:localize(@"custom_controls.button_edit.mouse_pass", nil)];
self.switchMousePass = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currentY - 5.0, 50.0, 30)];
[self.switchMousePass setOn:[self.targetButton.properties[@"passThruEnabled"] boolValue]];
[self.scrollView addSubview:self.switchMousePass];
currentY += labelMousePass.frame.size.height + 15.0;
// Property: Swipeable
currentY += labelName.frame.size.height + 12.0;
UILabel *labelSwipeable = [self addLabel:localize(@"custom_controls.button_edit.swipeable", nil)];
self.switchSwipeable = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currentY - 5.0, 50.0, 30)];
[self.switchSwipeable setOn:[self.targetButton.properties[@"isSwipeable"] boolValue]];
[self.scrollView addSubview:self.switchSwipeable];
// Property: Swipeable
UILabel *labelSwipeable = [self addLabel:localize(@"custom_controls.button_edit.swipeable", nil)];
self.switchSwipeable = [[UISwitch alloc] initWithFrame:CGRectMake(width - 62.0, currentY - 5.0, 50.0, 30)];
[self.switchSwipeable setOn:[self.targetButton.properties[@"isSwipeable"] boolValue]];
[self.scrollView addSubview:self.switchSwipeable];
currentY += labelSwipeable.frame.size.height + 15.0;
}
// Property: Background color
currentY += labelName.frame.size.height + 12.0;
UILabel *labelBGColor = [self addLabel:localize(@"custom_controls.button_edit.bg_color", nil)];
self.colorWellINTBackground = [[UIColorWell alloc] initWithFrame:CGRectMake(width - 42.0, currentY - 5.0, 30.0, 30.0)];
[self.colorWellINTBackground addTarget:self action:@selector(colorWellChanged) forControlEvents:UIControlEventValueChanged];
self.colorWellINTBackground.selectedColor = self.targetButton.backgroundColor;
[self.scrollView addSubview:self.colorWellINTBackground];
currentY += labelBGColor.frame.size.height + 15.0;
// Property: Stroke width
currentY += labelName.frame.size.height + 12.0;
UILabel *labelStrokeWidth = [self addLabel:localize(@"custom_controls.button_edit.stroke_width", nil)];
self.sliderStrokeWidth = [[DBNumberedSlider alloc] initWithFrame:CGRectMake(labelStrokeWidth.frame.size.width + 5.0, currentY - 5.0, width - labelStrokeWidth.frame.size.width - 5.0, 30.0)];
self.sliderStrokeWidth.continuous = YES;
self.sliderStrokeWidth.maximumValue = 100;
self.sliderStrokeWidth.maximumValue = MAX([self.targetButton.properties[@"width"] intValue], [self.targetButton.properties[@"height"] intValue]) / 2;
self.sliderStrokeWidth.tag = TAG_SLIDER_STROKEWIDTH;
self.sliderStrokeWidth.value = [self.targetButton.properties[@"strokeWidth"] intValue];
[self.sliderStrokeWidth addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
[self.scrollView addSubview:self.sliderStrokeWidth];
currentY += labelStrokeWidth.frame.size.height + 15.0;
// Property: Stroke color
currentY += labelName.frame.size.height + 12.0;
UILabel *labelStrokeColor = [self addLabel:localize(@"custom_controls.button_edit.stroke_color", nil)];
self.colorWellINTStroke = [[UIColorWell alloc] initWithFrame:CGRectMake(width - 42.0, currentY - 5.0, 30.0, 30.0)];
[self.colorWellINTStroke addTarget:self action:@selector(colorWellChanged) forControlEvents:UIControlEventValueChanged];
self.colorWellINTStroke.selectedColor = [[UIColor alloc] initWithCGColor:self.targetButton.layer.borderColor];
[self.scrollView addSubview:self.colorWellINTStroke];
currentY += labelStrokeColor.frame.size.height + 15.0;
// Property: Corner radius
currentY += labelName.frame.size.height + 12.0;
UILabel *labelCornerRadius = [self addLabel:localize(@"custom_controls.button_edit.corner_radius", nil)];
self.sliderCornerRadius = [[DBNumberedSlider alloc] initWithFrame:CGRectMake(labelCornerRadius.frame.size.width + 5.0, currentY - 5.0, width - labelCornerRadius.frame.size.width - 5.0, 30.0)];
self.sliderCornerRadius.continuous = YES;
self.sliderCornerRadius.maximumValue = 100;
self.sliderCornerRadius.tag = TAG_SLIDER_CORNERRADIUS;
self.sliderCornerRadius.value = [self.targetButton.properties[@"cornerRadius"] intValue];
[self.sliderCornerRadius addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
[self.scrollView addSubview:self.sliderCornerRadius];
if (![self.targetButton isKindOfClass:ControlJoystick.class]) {
UILabel *labelCornerRadius = [self addLabel:localize(@"custom_controls.button_edit.corner_radius", nil)];
self.sliderCornerRadius = [[DBNumberedSlider alloc] initWithFrame:CGRectMake(labelCornerRadius.frame.size.width + 5.0, currentY - 5.0, width - labelCornerRadius.frame.size.width - 5.0, 30.0)];
self.sliderCornerRadius.continuous = YES;
self.sliderCornerRadius.maximumValue = 100;
self.sliderCornerRadius.tag = TAG_SLIDER_CORNERRADIUS;
self.sliderCornerRadius.value = [self.targetButton.properties[@"cornerRadius"] intValue];
[self.sliderCornerRadius addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
[self.scrollView addSubview:self.sliderCornerRadius];
currentY += labelCornerRadius.frame.size.height + 15.0;
}
// Property: Button Opacity
currentY += labelName.frame.size.height + 12.0;
UILabel *labelOpacity = [self addLabel:localize(@"custom_controls.button_edit.opacity", nil)];
self.sliderOpacity = [[DBNumberedSlider alloc] initWithFrame:CGRectMake(labelOpacity.frame.size.width + 5.0, currentY - 5.0, width - labelOpacity.frame.size.width - 5.0, 30.0)];
self.sliderOpacity.continuous = YES;
@@ -844,9 +875,27 @@ CGFloat currentY;
self.sliderOpacity.value = [self.targetButton.properties[@"opacity"] floatValue] * 100.0;
[self.sliderOpacity addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
[self.scrollView addSubview:self.sliderOpacity];
currentY += labelOpacity.frame.size.height + 15.0;
currentY += labelName.frame.size.height + 12.0;
// Property: Visibility
self.arrVisibility = @[localize(@"Always", nil), localize(@"In game", nil), localize(@"In menu", nil)];
UILabel *labelVisibility = [self addLabel:localize(@"custom_controls.button_edit.visibility", nil)];
self.ctrlVisibility = [[UISegmentedControl alloc] initWithItems:self.arrVisibility];
[self.ctrlVisibility addTarget:self action:@selector(visibilityValueChanged:) forControlEvents:UIControlEventValueChanged];
self.ctrlVisibility.frame = CGRectMake(labelVisibility.frame.size.width + 5.0, currentY - 5.0, width - labelVisibility.frame.size.width - 5.0, 30.0);
BOOL displayInGame = [self.targetButton.properties[@"displayInGame"] boolValue];
BOOL displayInMenu = [self.targetButton.properties[@"displayInMenu"] boolValue];
if (displayInGame && displayInMenu) {
self.ctrlVisibility.selectedSegmentIndex = VISIBILITY_ALWAYS;
} else if (displayInGame) {
self.ctrlVisibility.selectedSegmentIndex = VISIBILITY_IN_GAME;
} else if (displayInMenu) {
self.ctrlVisibility.selectedSegmentIndex = VISIBILITY_IN_MENU;
} // else the segment is not chosen
[self.scrollView addSubview:self.ctrlVisibility];
currentY += labelVisibility.frame.size.height + 15.0;
self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width, currentY);
}
@@ -887,6 +936,9 @@ CGFloat currentY;
}
- (void)actionEditFinish {
if (self.switchFwdLock) {
self.targetButton.properties[@"forwardLock"] = @(self.switchFwdLock.isOn);
}
self.targetButton.properties[@"isToggle"] = @(self.switchToggleable.isOn);
self.targetButton.properties[@"passThruEnabled"] = @(self.switchMousePass.isOn);
self.targetButton.properties[@"isSwipeable"] = @(self.switchSwipeable.isOn);
@@ -906,24 +958,29 @@ CGFloat currentY;
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)orientationValueChanged {
- (void)orientationValueChanged:(UISegmentedControl *)sender {
((ControlDrawer *)self.targetButton).drawerData[@"orientation"] =
self.arrOrientation[self.ctrlOrientation.selectedSegmentIndex];
self.arrOrientation[sender.selectedSegmentIndex];
[(ControlDrawer *)self.targetButton syncButtons];
}
- (void)sliderValueChanged:(DBNumberedSlider *)sender {
[sender setValue:(NSInteger)sender.value animated:NO];
if (sender.tag == TAG_SLIDER_STROKEWIDTH) {
self.colorWellINTStroke.enabled = sender.value != 0;
self.targetButton.properties[@"strokeWidth"] = @((NSInteger) self.sliderStrokeWidth.value);
} else {
[sender setValue:(NSInteger)sender.value animated:NO];
self.targetButton.properties[@"cornerRadius"] = @((NSInteger) self.sliderCornerRadius.value);
self.targetButton.properties[@"opacity"] = @(self.sliderOpacity.value / 100.0);
}
[self.targetButton update];
}
- (void)visibilityValueChanged:(UISegmentedControl *)sender {
self.targetButton.properties[@"displayInGame"] = @(sender.selectedSegmentIndex != VISIBILITY_IN_MENU);
self.targetButton.properties[@"displayInMenu"] = @(sender.selectedSegmentIndex != VISIBILITY_IN_GAME);
}
#pragma mark - UIPickerView stuff
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
+1
View File
@@ -21,6 +21,7 @@ CGPoint lastVirtualMousePoint;
- (void)sendTouchPoint:(CGPoint)location withEvent:(int)event;
- (void)updateSavedResolution;
- (void)updateGrabState;
+ (BOOL)isRunning;
+50 -35
View File
@@ -5,10 +5,6 @@
#import "authenticator/BaseAuthenticator.h"
#import "customcontrols/ControlButton.h"
#import "customcontrols/ControlDrawer.h"
// Incomplete
#ifdef INTERNAL_VIRTUAL_JOYSTICK
#import "customcontrols/ControlJoystick.h"
#endif
#import "customcontrols/ControlSubButton.h"
#import "customcontrols/CustomControlsUtils.h"
@@ -60,7 +56,7 @@ BOOL slideableHotbar;
@property(nonatomic) CGFloat screenScale;
@property(nonatomic) CGFloat mouseSpeed;
@property(nonatomic) CGRect clickRange;
@property(nonatomic) BOOL isMacCatalystApp, shouldTriggerClick, shouldTriggerHaptic;
@property(nonatomic) BOOL isMacCatalystApp, shouldTriggerClick, shouldTriggerHaptic, toggleHidden;
@property(nonatomic) BOOL enableMouseGestures, enableHotbarGestures;
@@ -265,14 +261,6 @@ BOOL slideableHotbar;
[self updateJetsamControl];
[self updatePreferenceChanges];
[self loadCustomControls];
[self executebtn_special_togglebtn:0];
#ifdef INTERNAL_VIRTUAL_JOYSTICK
// just for testing
ControlJoystick *joystick = ControlJoystick.buttonWithDefaultProperties;
[self.ctrlView addSubview:joystick];
[joystick update];
#endif
if (UIApplication.sharedApplication.connectedScenes.count > 1 &&
getPrefBool(@"video.fullscreen_airplay")) {
@@ -388,6 +376,40 @@ BOOL slideableHotbar;
CallbackBridge_nativeSendScreenSize(windowWidth, windowHeight);
}
- (void)updateControlHiddenState:(BOOL)hide {
for (UIView *view in self.ctrlView.subviews) {
ControlButton *button = (ControlButton *)view;
if (!button.canBeHidden) continue;
BOOL hidden = hide || !(
(isGrabbing && [button.properties[@"displayInGame"] boolValue]) ||
(!isGrabbing && [button.properties[@"displayInMenu"] boolValue]));
if (!hidden && ![button isKindOfClass:ControlSubButton.class]) {
button.hidden = hidden;
if ([button isKindOfClass:ControlDrawer.class]) {
[(ControlDrawer *)button restoreButtonVisibility];
}
} else if (hidden) {
button.hidden = hidden;
}
}
}
- (void)updateGrabState {
// Update cursor position
if (isGrabbing == JNI_TRUE) {
CGFloat screenScale = self.surfaceView.layer.contentsScale;
CallbackBridge_nativeSendCursorPos(ACTION_DOWN, lastVirtualMousePoint.x * screenScale, lastVirtualMousePoint.y * screenScale);
virtualMouseFrame.origin.x = self.view.frame.size.width / 2;
virtualMouseFrame.origin.y = self.view.frame.size.height / 2;
self.mousePointerView.frame = virtualMouseFrame;
}
self.scrollPanGesture.enabled = !isGrabbing;
self.mousePointerView.hidden = isGrabbing || !virtualMouseEnabled;
// Update buttons visibility
[self updateControlHiddenState:NO];
}
- (void)launchMinecraft {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSDictionary *version = @{@"id": PLProfiles.current.selectedProfile[@"lastVersionId"]};
@@ -412,6 +434,8 @@ BOOL slideableHotbar;
[self.swipeableButtons removeAllObjects];
NSString *controlFile = [PLProfiles resolveKeyForCurrentProfile:@"defaultTouchCtrl"];
[self.ctrlView loadControlFile:controlFile];
ControlButton *menuButton;
for (ControlButton *button in self.ctrlView.subviews) {
BOOL isSwipeable = [button.properties[@"isSwipeable"] boolValue];
@@ -419,8 +443,10 @@ BOOL slideableHotbar;
BOOL isMenuButton = NO;
for (int i = 0; i < 4; i++) {
int keycodeInt = [button.properties[@"keycodes"][i] intValue];
button.canBeHidden &= keycodeInt != SPECIALBTN_TOGGLECTRL;
isMenuButton |= keycodeInt == SPECIALBTN_MENU;
button.canBeHidden &= keycodeInt != SPECIALBTN_TOGGLECTRL && keycodeInt != SPECIALBTN_VIRTUALMOUSE;
if (keycodeInt == SPECIALBTN_MENU) {
menuButton = button;
}
}
[button addTarget:self action:@selector(executebtn_down:) forControlEvents:UIControlEventTouchDown];
@@ -433,17 +459,20 @@ BOOL slideableHotbar;
[button addGestureRecognizer:panRecognizerButton];
[self.swipeableButtons addObject:button];
}
}
if (!isMenuButton) continue;
[self updateControlHiddenState:self.toggleHidden];
if (menuButton) {
NSMutableArray *items = [NSMutableArray new];
for (int i = 0; i < self.menuArray.count; i++) {
UIAction *item = [UIAction actionWithTitle:localize(self.menuArray[i], nil) image:nil identifier:nil
handler:^(id action) {[self didSelectMenuItem:i];}];
[items addObject:item];
}
button.menu = [UIMenu menuWithTitle:@"" image:nil identifier:nil
menuButton.menu = [UIMenu menuWithTitle:@"" image:nil identifier:nil
options:UIMenuOptionsDisplayInline children:items];
button.showsMenuAsPrimaryAction = YES;
menuButton.showsMenuAsPrimaryAction = YES;
self.edgeGesture.enabled = NO;
}
}
@@ -780,7 +809,6 @@ BOOL slideableHotbar;
#pragma mark - On-screen button functions
int currentVisibility = 1;
- (void)executebtn:(ControlButton *)sender withAction:(int)action {
int held = action == ACTION_DOWN;
for (int i = 0; i < 4; i++) {
@@ -924,22 +952,9 @@ int currentVisibility = 1;
}
- (void)executebtn_special_togglebtn:(int)held {
if (held == 0) {
currentVisibility = !currentVisibility;
for (UIView *view in self.ctrlView.subviews) {
ControlButton *button = (ControlButton *)view;
if (button.canBeHidden) {
if (!currentVisibility && ![button isKindOfClass:[ControlSubButton class]]) {
button.hidden = currentVisibility;
if ([button isKindOfClass:[ControlDrawer class]]) {
[(ControlDrawer *)button restoreButtonVisibility];
}
} else if (currentVisibility) {
button.hidden = currentVisibility;
}
}
}
}
if (held) return;
self.toggleHidden = !self.toggleHidden;
[self updateControlHiddenState:self.toggleHidden];
}
#pragma mark - Input: On-screen touch events
+2 -1
View File
@@ -11,12 +11,13 @@
@interface ControlButton : UIButton {
}
@property BOOL canBeHidden, isToggleOn;
@property BOOL canBeHidden, displayInGame, displayInMenu, isToggleOn;
@property(nonatomic) NSMutableDictionary* properties;
@property(nonatomic) UIColor* savedBackgroundColor;
+ (id)buttonWithProperties:(NSMutableDictionary *)propArray;
- (CGFloat)calculateDynamicPos:(NSString *)string;
- (BOOL)canSnap:(ControlButton *)button;
- (NSString *)generateDynamicX:(CGFloat)x;
- (NSString *)generateDynamicY:(CGFloat)y;
+9 -3
View File
@@ -29,6 +29,7 @@
//NSLog(@"DBG button prop = %@", propArray);
ControlButton *instance = [self buttonWithType:UIButtonTypeSystem];
instance.autoresizingMask = UIViewAutoresizingFlexibleWidth;
instance.clipsToBounds = YES;
instance.tintColor = [UIColor whiteColor];
instance.titleLabel.adjustsFontSizeToFitWidth = YES;
instance.titleLabel.lineBreakMode = NSLineBreakByCharWrapping;
@@ -151,6 +152,9 @@
- (void)update {
NSAssert(self.superview != nil, @"should not be nil");
self.displayInGame = [self.properties[@"displayInGame"] boolValue];
self.displayInMenu = [self.properties[@"displayInMenu"] boolValue];
// net/kdt/pojavlaunch/customcontrols/ControlData.update()
[self preProcessProperties];
@@ -179,10 +183,12 @@
self.layer.borderColor = [convertARGB2UIColor(propStrokeColor) CGColor];
self.layer.cornerRadius = MIN(self.frame.size.width, self.frame.size.height) / 200.0 * propCornerRadius;
self.layer.borderWidth = MAX(self.frame.size.width, self.frame.size.height) / 200.0 * propStrokeWidth;
self.clipsToBounds = YES;
self.layer.borderWidth = propStrokeWidth;
[self setTitle:self.properties[@"name"] forState:UIControlStateNormal];
[UIView performWithoutAnimation:^{
[self setTitle:self.properties[@"name"] forState:UIControlStateNormal];
[self layoutIfNeeded];
}];
}
// NOTE: Unlike Android's impl, this method uses dp instead of px (no call to dpToPx), "view.center" instead of "view.pos + view.size/2"
+3 -4
View File
@@ -39,13 +39,12 @@
// NOTE: Unlike Android's impl, this method uses dp instead of px (no call to dpToPx)
- (void)alignButtons {
NSString *orientation = (NSString *)self.drawerData[@"orientation"];
if ([orientation isEqualToString:@"FREE"]) {
return;
}
for (int i = 0; i < self.buttons.count; i++) {
ControlButton *button = self.buttons[i];
if ([orientation isEqualToString:@"RIGHT"]) {
if ([orientation isEqualToString:@"FREE"]) {
// Do nothing but call update
} else if ([orientation isEqualToString:@"RIGHT"]) {
button.properties[@"dynamicX"] = [self generateDynamicX:self.frame.origin.x + ([self.properties[@"width"] floatValue] + 2.0) * (i+1)];
button.properties[@"dynamicY"] = [self generateDynamicY:self.frame.origin.y];
} else if ([orientation isEqualToString:@"LEFT"]) {
+8
View File
@@ -0,0 +1,8 @@
#import "ControlButton.h"
@interface ControlJoystick : ControlButton {
}
+ (id)buttonWithDefaultProperties;
@end
+240
View File
@@ -0,0 +1,240 @@
#import "ControlJoystick.h"
#import "CustomControlsUtils.h"
#import "../input/ControllerInput.h"
#import "../UIKit+hook.h"
#import "../utils.h"
#include "../glfw_keycodes.h"
// Left thumbstick directions
#define DIRECTION_EAST 0
#define DIRECTION_NORTH_EAST 1
#define DIRECTION_NORTH 2
#define DIRECTION_NORTH_WEST 3
//#define DIRECTION_WEST 4
#define DIRECTION_SOUTH_WEST 5
//#define DIRECTION_SOUTH 6
#define DIRECTION_SOUTH_EAST 7
extern BOOL leftShiftHeld;
extern CGFloat lastXValue; // lastHorizontalValue
extern CGFloat lastYValue; // lastVerticalValue
// From CustomControlsUtils
NSMutableDictionary* createButton(NSString* name, int* keycodes, NSString* dynamicX, NSString* dynamicY, CGFloat width, CGFloat height);
@interface ControlJoystick()
@property(nonatomic) UIView *background, *thumb;
@property(nonatomic) UIButton *fwdLockView;
@property(nonatomic) CGPoint mCenter;
@end
@implementation ControlJoystick
+ (id)buttonWithDefaultProperties {
NSMutableDictionary *properties = createButton(@"", (int[4]){0,0,0,0 /* GLFW_KEY_W, GLFW_KEY_A, GLFW_KEY_S, GLFW_KEY_D */}, @"${margin}", @"${bottom} - ${margin}", 200, 200);
properties[@"cornerRadius"] = @100;
properties[@"bgColor"] = @(0x77111111);
ControlJoystick *instance = [self buttonWithProperties:properties];
return instance;
}
+ (id)buttonWithProperties:(NSMutableDictionary *)propArray {
ControlJoystick *instance = [super buttonWithProperties:propArray];
instance.clipsToBounds = NO;
instance.background = [UIView new];
instance.thumb = [UIView new];
instance.thumb.backgroundColor = UIColor.blackColor;
[instance addSubview:instance.background];
[instance addSubview:instance.thumb];
if (!isControlModifiable && [propArray[@"forwardLock"] boolValue]) {
instance.fwdLockView = [UIButton buttonWithType:UIButtonTypeCustom];
instance.fwdLockView.hidden = YES;
instance.fwdLockView.imageEdgeInsets = UIEdgeInsetsMake(4, 4, 4, 4);
instance.fwdLockView.tintColor = UIColor.whiteColor;
instance.fwdLockView.userInteractionEnabled = NO;
[instance addSubview:instance.fwdLockView];
}
return instance;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (isControlModifiable || touches.count != 1) return;
if (touches.anyObject.view == self) {
self.thumb.center = [touches.anyObject locationInView:self];
}
if (isGrabbing && self.fwdLockView) {
self.fwdLockView.center = CGPointMake(self.mCenter.x, -self.mCenter.y);
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (isControlModifiable || touches.count != 1) return;
UITouch *touch = touches.anyObject;
//CGPoint prev = [touches.anyObject previousLocationInView:self];
//CGPoint loc = [touches.anyObject locationInView:self];
CGPoint center = [touches.anyObject locationInView:self];
//self.thumb.center;
//center.x += loc.x - prev.x;
//center.y += loc.y - prev.y;
CGFloat dirX = center.x - self.mCenter.x;
CGFloat dirY = center.y - self.mCenter.y;
CGFloat radius = sqrt(dirX*dirX + dirY*dirY);
CGFloat maxRadius = MIN(self.mCenter.x, self.mCenter.y) - self.thumb.frame.size.width/2;
if (radius > maxRadius) {
center.x = dirX*maxRadius/radius + self.mCenter.x;
center.y = dirY*maxRadius/radius + self.mCenter.y;
}
self.thumb.center = center;
CGFloat deadzone = 0.35;
if (!isGrabbing || radius >= maxRadius*deadzone) {
[self callbackMoveX:((center.x / self.frame.size.width)*2-1) Y:((-center.y / self.frame.size.height)*2+1)];
}
#ifdef DEBUG_JOYSTICK
[UIView performWithoutAnimation:^{
[self setTitle:[NSString stringWithFormat:@"rad=%f\nCX=%f\nCY=%f", radius, self.mCenter.x / radius, self.mCenter.y / radius] forState:UIControlStateNormal];
[self layoutIfNeeded];
}];
#endif
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (isControlModifiable) return;
lastXValue = lastYValue = 0;
if (isGrabbing && self.fwdLockView && CGRectContainsPoint(self.fwdLockView.frame, [touches.anyObject locationInView:self])) {
self.fwdLockView.center = self.thumb.center;
} else {
self.thumb.center = self.mCenter;
[self callbackMoveX:0 Y:0];
}
}
- (void)callbackMoveX:(CGFloat)xValue Y:(CGFloat)yValue {
#ifdef DEBUG_JOYSTICK
static UILabel *debugLabel;
if (debugLabel == nil) {
debugLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
debugLabel.lineBreakMode = NSLineBreakByWordWrapping;
debugLabel.numberOfLines = 0;
debugLabel.userInteractionEnabled = NO;
[currentWindow() addSubview:debugLabel];
}
#endif
if (!isGrabbing) {
// Update virtual mouse position
lastXValue = xValue;
lastYValue = yValue;
return;
}
static char lastDirection = -2;
char direction = -1;
if (xValue != 0 && yValue != 0) {
CGFloat degree = atan2f(yValue, xValue) * (180.0 / M_PI);
if (degree < 0) {
degree += 360;
}
direction = (int)((degree+22.5)/45.0) % 8;
#ifdef DEBUG_JOYSTICK
debugLabel.text = [NSString stringWithFormat:@"x=%f\ny=%f\natan=%f\ndeg=%f\ndirection=%d, last=%d\npressW=%d A=%d S=%d D=%d", atan2f(yValue, xValue), xValue, yValue, degree, direction, lastDirection,
direction >= DIRECTION_NORTH_EAST &&
direction <= DIRECTION_NORTH_WEST,
direction >= DIRECTION_NORTH_WEST &&
direction <= DIRECTION_SOUTH_WEST,
direction >= DIRECTION_SOUTH_WEST &&
direction <= DIRECTION_SOUTH_EAST,
direction == DIRECTION_SOUTH_EAST ||
direction == DIRECTION_EAST ||
direction == DIRECTION_NORTH_EAST];
#endif
}
if (lastDirection == direction) {
return;
}
// Update WASD states
int mod = leftShiftHeld ? GLFW_MOD_SHIFT : 0;
CallbackBridge_nativeSendKey(GLFW_KEY_W, 0,
direction >= DIRECTION_NORTH_EAST &&
direction <= DIRECTION_NORTH_WEST,
mod);
CallbackBridge_nativeSendKey(GLFW_KEY_A, 0,
direction >= DIRECTION_NORTH_WEST &&
direction <= DIRECTION_SOUTH_WEST,
mod);
CallbackBridge_nativeSendKey(GLFW_KEY_S, 0,
direction >= DIRECTION_SOUTH_WEST &&
direction <= DIRECTION_SOUTH_EAST,
mod);
CallbackBridge_nativeSendKey(GLFW_KEY_D, 0,
direction == DIRECTION_SOUTH_EAST ||
direction == DIRECTION_EAST ||
direction == DIRECTION_NORTH_EAST,
mod);
self.fwdLockView.hidden = direction != DIRECTION_NORTH;
lastDirection = direction;
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
self.mCenter = CGPointMake(frame.size.width/2, frame.size.height/2);
CGFloat minSize = MIN(frame.size.width, frame.size.height);
self.fwdLockView.frame = CGRectMake(0, 0, minSize/4, minSize/4);
[self.fwdLockView setImage:[UIImage systemImageNamed:@"lock"] forState:UIControlStateNormal];
self.fwdLockView.layer.cornerRadius = self.fwdLockView.frame.size.width/2;
self.thumb.frame = CGRectMake(0, 0, minSize/4, minSize/4);
self.thumb.center = self.mCenter;
self.thumb.layer.cornerRadius = self.thumb.frame.size.width/2;
CGFloat bgSize = minSize - self.thumb.frame.size.width + self.background.layer.borderWidth/2;
self.background.frame = CGRectMake(0, 0, bgSize, bgSize);
self.background.layer.cornerRadius = bgSize/2;
self.background.center = self.mCenter;
}
- (void)update {
NSAssert(self.superview != nil, @"should not be nil");
self.displayInGame = [self.properties[@"displayInGame"] boolValue];
self.displayInMenu = [self.properties[@"displayInMenu"] boolValue];
// net/kdt/pojavlaunch/customcontrols/ControlData.update()
[self preProcessProperties];
NSString *propDynamicX = (NSString *) self.properties[@"dynamicX"];
NSString *propDynamicY = (NSString *) self.properties[@"dynamicY"];
CGFloat propW = [self.properties[@"width"] floatValue];
CGFloat propH = [self.properties[@"height"] floatValue];
float propStrokeWidth = [self.properties[@"strokeWidth"] floatValue];
int propBackgroundColor = [self.properties[@"bgColor"] intValue];
int propStrokeColor = [self.properties[@"strokeColor"] intValue];
self.background.backgroundColor = self.fwdLockView.backgroundColor = convertARGB2UIColor(propBackgroundColor);
self.background.layer.borderColor = [convertARGB2UIColor(propStrokeColor) CGColor];
self.background.layer.borderWidth = propStrokeWidth + 1;
// Calculate dynamic position
CGFloat propX = [self calculateDynamicPos:propDynamicX];
CGFloat propY = [self calculateDynamicPos:propDynamicY];
// Update other properties
self.frame = CGRectMake(propX, propY, propW, propH);
self.alpha = [self.properties[@"opacity"] floatValue];
self.alpha = MAX(self.alpha, isControlModifiable ? 0.1 : 0.01);
self.layer.cornerRadius = MIN(self.frame.size.width, self.frame.size.height) / 2.0;
}
@end
@@ -17,6 +17,11 @@
- (void)setParentDrawer:(ControlDrawer *)drawer {
_parentDrawer = drawer;
// Copy visibility properties
self.displayInGame = drawer.displayInGame;
self.displayInMenu = drawer.displayInMenu;
[self preProcessProperties];
//NSLog(@"DEBUG: SubButton properties %@", self.properties);
}
+45 -4
View File
@@ -1,4 +1,5 @@
#import "ControlDrawer.h"
#import "ControlJoystick.h"
#import "ControlSubButton.h"
#import "CustomControlsUtils.h"
#import "../LauncherPreferences.h"
@@ -20,6 +21,8 @@ NSMutableDictionary* createButton(NSString* name, int* keycodes, NSString* dynam
dict[@"opacity"] = @(1);
dict[@"cornerRadius"] = @(0);
dict[@"bgColor"] = @(0x4d000000);
dict[@"displayInGame"] = @YES;
dict[@"displayInMenu"] = @YES;
return dict;
}
@@ -56,6 +59,28 @@ int convertUIColor2RGB(UIColor* color) {
return (0xFF << 24) | (r << 16) | (g << 8) | (b << 0);
}
static int computeStrokeWidth(float widthInPercent, float width, float height) {
CGFloat maxSize = MAX(width, height);
return (int) ((maxSize / 2) * (widthInPercent / 100));
}
void convertV3_4Layout(NSMutableDictionary* dict) {
// Convert the layout stroke width to the V5 form
for (NSMutableDictionary *button in (NSMutableArray *)dict[@"mControlDataList"]) {
button[@"strokeWidth"] = @(computeStrokeWidth([button[@"strokeWidth"] intValue], [button[@"width"] intValue], [button[@"height"] intValue]));
}
// Add default values
for (NSString *key in @[@"mControlDataList", @"mDrawerDataList"]) {
for (NSMutableDictionary *button in (NSMutableArray *)dict[key]) {
button[@"displayInGame"] = @YES;
button[@"displayInMenu"] = @YES;
}
}
dict[@"version"] = @(6);
}
void convertV2Layout(NSMutableDictionary* dict) {
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGFloat screenScale = [[UIScreen mainScreen] scale];
@@ -83,6 +108,7 @@ void convertV2Layout(NSMutableDictionary* dict) {
}
dict[@"version"] = @(5);
convertV3_4Layout(dict);
}
void convertV1Layout(NSMutableDictionary* dict) {
@@ -155,9 +181,12 @@ BOOL convertLayoutIfNecessary(NSMutableDictionary* dict) {
case 3:
case 4:
case 5:
convertV3_4Layout(dict);
break;
case 6:
break;
default:
showDialog(localize(@"custom_controls.control_menu.save.error.json", nil), [NSString stringWithFormat:localize(@"custom_controls.error.imcompatible", nil), version]);
showDialog(localize(@"custom_controls.control_menu.save.error.json", nil), [NSString stringWithFormat:localize(@"custom_controls.error.incompatible", nil), version]);
return NO;
}
return YES;
@@ -169,12 +198,13 @@ void generateAndSaveDefaultControl() {
return;
}
// Generate a v2.6 control
// Generate a v2.7 control
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
dict[@"version"] = @(5);
dict[@"scaledAt"] = @(100);
dict[@"mControlDataList"] = [[NSMutableArray alloc] init];
dict[@"mDrawerDataList"] = [[NSMutableArray alloc] init];
dict[@"mControlDataList"] = [NSMutableArray new];
dict[@"mDrawerDataList"] = [NSMutableArray new];
dict[@"mJoystickDataList"] = [NSMutableArray new];
[dict[@"mControlDataList"] addObject:createButton(@"Keyboard",
(int[]){SPECIALBTN_KEYBOARD,0,0,0},
@"${margin} * 3 + ${width} * 2",
@@ -405,6 +435,17 @@ void loadControlObject(UIView* targetView, NSMutableDictionary* controlDictionar
[drawer update];
}
NSMutableArray *joystickDataList = controlDictionary[@"mJoystickDataList"];
for (NSMutableDictionary *joystickDict in joystickDataList) {
@try {
ControlJoystick *button = [ControlJoystick buttonWithProperties:joystickDict];
[targetView addSubview:button];
[button update];
} @catch (NSException *exception) {
[errorString appendFormat:@"%@: %@\n", @"ControlJoystick", exception.reason];
}
}
controlDictionary[@"scaledAt"] = getPrefObject(@"control.button_scale");
if (errorString.length > 0) {
+1 -11
View File
@@ -358,17 +358,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(JNIE
dispatch_async(dispatch_get_main_queue(), ^{
SurfaceViewController *vc = ((SurfaceViewController *)currentWindow().rootViewController);
UIView *surfaceView = vc.surfaceView;
if (isGrabbing == JNI_TRUE) {
CGFloat screenScale = [[UIScreen mainScreen] scale] * resolutionScale;
CallbackBridge_nativeSendCursorPos(ACTION_DOWN, lastVirtualMousePoint.x * screenScale, lastVirtualMousePoint.y * screenScale);
CGRect screenBounds = [[UIScreen mainScreen] bounds];
virtualMouseFrame.origin.x = screenBounds.size.width / 2;
virtualMouseFrame.origin.y = screenBounds.size.height / 2;
vc.mousePointerView.frame = virtualMouseFrame;
}
vc.scrollPanGesture.enabled = !isGrabbing;
vc.mousePointerView.hidden = isGrabbing || !virtualMouseEnabled;
[vc updateGrabState];
});
}
@@ -28,7 +28,12 @@
"Move" = "Move";
"Remove" = "Remove";
"Resize" = "Resize";
// Visibility
"Always" = "Always";
"In game" = "In game";
"In menu" = "In menu";
"custom_controls.button_edit.forward_lock" = "Forward lock";
"custom_controls.button_edit.name" = "Name";
"custom_controls.button_edit.size" = "Size";
"custom_controls.button_edit.mapping" = "Mapping";
@@ -37,17 +42,17 @@
"custom_controls.button_edit.mouse_pass" = "Mouse pass";
"custom_controls.button_edit.swipeable" = "Swipeable";
"custom_controls.button_edit.bg_color" = "Background color";
"custom_controls.button_edit.stroke_width" = "Stroke width (%)";
"custom_controls.button_edit.stroke_width" = "Stroke width (dp)";
"custom_controls.button_edit.stroke_color" = "Stroke color";
"custom_controls.button_edit.corner_radius" = "Corner radius (%)";
"custom_controls.button_edit.opacity" = "Opacity (%)";
"custom_controls.button_edit.visibility" = "Visibility";
"custom_controls.button_menu.add_subbutton" = "Add sub-button";
"custom_controls.control_menu.discard_changes" = "Discard changes";
"custom_controls.control_menu.exit" = "Exit";
"custom_controls.control_menu.exit.warn" = "You are about to exit without saving changes.";
"custom_controls.control_menu.save" = "Save";
"custom_controls.control_menu.save.error.default" = "Control name can not be \"default\" as it will be overwritten.";
"custom_controls.control_menu.save.error.json" = "JSON error";
"custom_controls.control_menu.save.error.write" = "Error saving file";
"custom_controls.control_menu.load" = "Load";
@@ -55,6 +60,7 @@
"custom_controls.control_menu.safe_area" = "Safe area";
"custom_controls.control_menu.add_button" = "Add button";
"custom_controls.control_menu.add_drawer" = "Add drawer";
"custom_controls.control_menu.add_joystick" = "Add joystick";
"custom_controls.error.incompatible" = "This control version (code %d) is not implemented in this launcher build.";
"custom_controls.hint" = "Long-press anywhere on screen for more options";