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:
1 parent
63261cf60a
commit
36c3e312f3
14 files changed
+517
-139
No files matched your search
@@ -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];
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@ CGPoint lastVirtualMousePoint;
|
||||
|
||||
- (void)sendTouchPoint:(CGPoint)location withEvent:(int)event;
|
||||
- (void)updateSavedResolution;
|
||||
- (void)updateGrabState;
|
||||
|
||||
+ (BOOL)isRunning;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"]) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#import "ControlButton.h"
|
||||
|
||||
@interface ControlJoystick : ControlButton {
|
||||
}
|
||||
|
||||
+ (id)buttonWithDefaultProperties;
|
||||
|
||||
@end
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
Reference in new issue
Block a user