- feat: slide & hold mode for slidable buttons

This commit is contained in:
TrueZhuanjia
2025-08-10 13:22:30 +08:00
parent 88c0e358aa
commit 3536bf06ba
8 changed files with 74 additions and 31 deletions
+6 -5
View File
@@ -1518,19 +1518,20 @@
<nil key="highlightedColor"/>
</label>
<segmentedControl opaque="NO" alpha="0.76999998092651367" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="cKS-fy-Zpg">
<rect key="frame" x="160" y="0.0" width="244" height="32"/>
<rect key="frame" x="160" y="0.0" width="367" height="32"/>
<color key="backgroundColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<segments>
<segment title="yes"/>
<segment title="no"/>
<segment title="toggle"/>
<segment title="slide &amp; hold"/>
<segment title="disabled"/>
</segments>
<color key="tintColor" systemColor="systemGray3Color"/>
<color key="selectedSegmentTintColor" red="0.23087820410000001" green="0.4576539993" blue="0.51765710119999997" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</segmentedControl>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" " textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dOF-FW-cBU" userLabel="uiLabel">
<rect key="frame" x="404" y="0.0" width="246" height="31"/>
<rect key="frame" x="527" y="0.0" width="123" height="31"/>
<constraints>
<constraint firstAttribute="width" constant="246" id="hfV-um-PjK"/>
<constraint firstAttribute="width" constant="123" id="hfV-um-PjK"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -387,7 +387,7 @@ static CGRect layoutViewBounds;
buttonState.stickIndicatorOffset = widgetView.stickIndicatorOffset;
buttonState.widgetShape = widgetView.shape;
buttonState.minStickOffset = widgetView.minStickOffset;
buttonState.isSlidable = widgetView.isSlidable;
buttonState.slideMode = widgetView.slideMode;
NSData *buttonStateEncoded = [NSKeyedArchiver archivedDataWithRootObject:buttonState requiringSecureCoding:YES error:nil];
[buttonStatesEncoded addObject: buttonStateEncoded];
@@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
@property NSString *alias;
@property CGPoint position;
@property (nonatomic, assign) BOOL isHidden;
@property (nonatomic, assign) BOOL isSlidable;
@property (nonatomic, assign) uint8_t slideMode;
@property (nonatomic, assign) uint8_t buttonType;
@property (nonatomic, assign) CGFloat widthFactor; // for OnScreenWidgetView
@property (nonatomic, assign) CGFloat heightFactor; // for OnScreenWidgetView
@@ -57,6 +57,13 @@ typedef NS_ENUM(NSInteger, MouseButtonAction) {
rightButtonDown,
};
typedef NS_ENUM(NSInteger, ButtonSlideMode) {
toggle,
slideAndHold,
disabled
};
- (id) initWithButtonName:(NSString*)name buttonType:(uint8_t)buttonType andPosition:(CGPoint)position;
@@ -35,9 +35,9 @@
[encoder encodeInt:self.buttonType forKey:@"buttonType"];
[encoder encodeInt:self.vibrationStyle forKey:@"vibrationStyle"];
[encoder encodeInt:self.mouseButtonAction forKey:@"mouseButtonAction"];
[encoder encodeInt:self.slideMode forKey:@"slideMode"];
[encoder encodeCGPoint:self.position forKey:@"position"];
[encoder encodeBool:self.isHidden forKey:@"isHidden"];
[encoder encodeBool:self.isSlidable forKey:@"isSlidable"];
[encoder encodeFloat:self.widthFactor forKey:@"widthFactor"];
[encoder encodeFloat:self.heightFactor forKey:@"heightFactor"];
[encoder encodeFloat:self.sensitivityFactorX forKey:@"sensitivityFactorX"];
@@ -58,9 +58,9 @@
self.buttonType = [decoder decodeIntForKey:@"buttonType"];
self.vibrationStyle = [decoder decodeIntForKey:@"vibrationStyle"];
self.mouseButtonAction = [decoder decodeIntForKey:@"mouseButtonAction"];
self.slideMode = [decoder containsValueForKey:@"slideMode"] ? [decoder decodeIntForKey:@"slideMode"] : 0;
self.position = [decoder decodeCGPointForKey:@"position"];
self.isHidden = [decoder decodeBoolForKey:@"isHidden"];
self.isSlidable = [decoder containsValueForKey:@"isSlidable"] ? [decoder decodeBoolForKey:@"isSlidable"] : YES;
self.widthFactor = [decoder decodeFloatForKey:@"widthFactor"];
self.heightFactor = [decoder decodeFloatForKey:@"heightFactor"];
self.sensitivityFactorX = [decoder decodeFloatForKey:@"sensitivityFactorX"];
+12 -7
View File
@@ -45,7 +45,7 @@ import UIKit
@objc public var pressed: Bool
@objc public var widthFactor: CGFloat = 1.0
@objc public var heightFactor: CGFloat = 1.0
@objc public var isSlidable: Bool = true
@objc public var slideMode: Int = 0
@objc public var deNormalizedWidthFactor: CGFloat = 1.0
@objc public var deNormalizedHeightFactor: CGFloat = 1.0
@@ -1208,7 +1208,7 @@ import UIKit
for touch in touches {
for subview in self.superview?.subviews ?? [] {
if let widget = subview as? OnScreenWidgetView{
if !widget.capturedTouches.contains(touch) || !widget.isSlidable {continue}
if !widget.capturedTouches.contains(touch) || widget.slideMode == ButtonSlideMode.disabled.rawValue {continue}
widget.handlebuttonUp()
}
}
@@ -1223,16 +1223,21 @@ import UIKit
if widget.widgetType != WidgetTypeEnum.button {continue}
let pointInSubview = widget.convert(locationInSuperView, from: self.superview)
if widget.bounds.contains(pointInSubview){
if widget.capturedTouches.contains(touch) || !widget.isSlidable {continue}
if widget.capturedTouches.contains(touch) || widget.slideMode == ButtonSlideMode.disabled.rawValue {continue}
widget.capturedTouches.add(touch)
widget.handleButtonDown()
// print("UIButton: \(widget.buttonLabel) in, \(widget.touchPadString), \(CACurrentMediaTime())")
}
else{
if !widget.capturedTouches.contains(touch) || !widget.isSlidable {continue}
if !widget.capturedTouches.contains(touch) || widget.slideMode == ButtonSlideMode.disabled.rawValue {continue}
// print("UIButton: \(widget.buttonLabel) out test, \(widget.touchPadString), \(CACurrentMediaTime())")
widget.capturedTouches.remove(touch)
widget.handlebuttonUp()
if(widget.slideMode == ButtonSlideMode.toggle.rawValue){
widget.capturedTouches.remove(touch)
widget.handlebuttonUp()
}
if(widget.slideMode == ButtonSlideMode.slideAndHold.rawValue){
// do nothing here
}
}
}
}
@@ -1248,7 +1253,7 @@ import UIKit
}
if !self.buttonString.isEmpty{
if self.isSlidable {self.handleButtonSliding(touches: touches)}
if self.slideMode != ButtonSlideMode.disabled.rawValue {self.handleButtonSliding(touches: touches)}
}
if CommandManager.specialOverlayButtonCmds.contains(self.cmdString){
+1 -1
View File
@@ -454,7 +454,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
widgetView.trackballDecelerationRate = buttonState.decelerationRate;
widgetView.stickIndicatorOffset = buttonState.stickIndicatorOffset;
widgetView.minStickOffset = buttonState.minStickOffset;
widgetView.isSlidable = buttonState.isSlidable;
widgetView.slideMode = buttonState.slideMode;
// Add the widgetView to the view controller's view
[self->streamFrameTopLayerView addSubview:widgetView]; // add keyboard button to the stream frame view. must add it to the target view before setting location.
buttonState.position = [self denormalizeWidgetPosition:buttonState.position];
@@ -123,7 +123,7 @@
widgetView.trackballDecelerationRate = buttonState.decelerationRate;
widgetView.stickIndicatorOffset = buttonState.stickIndicatorOffset;
widgetView.minStickOffset = buttonState.minStickOffset;
widgetView.isSlidable = buttonState.isSlidable;
widgetView.slideMode = buttonState.slideMode;
// Add the widgetView to the view controller's view
[self.view insertSubview:widgetView belowSubview:self.widgetPanelStack];
buttonState.position = [self denormalizeWidgetPosition:buttonState.position];
@@ -635,7 +635,7 @@
newWidget.minStickOffset = [widgetInitParams[@"minStickOffsetString"] floatValue];
[newWidget setVibrationWithStyle:widget.vibrationStyle];
newWidget.mouseButtonAction = widget.mouseButtonAction;
newWidget.isSlidable = widget.isSlidable;
newWidget.slideMode = widget.slideMode;
[self.view insertSubview:newWidget belowSubview:self.widgetPanelStack];
if(createNew) [newWidget setLocationWithPosition:CGPointMake(90, 130)];
@@ -753,7 +753,7 @@
[self.widgetBorderWidthSlider setValue:self->selectedWidgetView.borderWidth];
self.slidableStack.hidden = selectedWidgetView.widgetType != WidgetTypeEnumButton;
[self.slidableSelector setSelectedSegmentIndex:selectedWidgetView.isSlidable ? 0 : 1];
[self.slidableSelector setSelectedSegmentIndex:selectedWidgetView.slideMode];
bool showSensitivityFactorStack = selectedWidgetView.hasSensitivityTweak;
bool showStickIndicatorOffsetStack = selectedWidgetView.hasStickIndicator;
@@ -906,9 +906,9 @@
}
}
- (void)slidableChanged:(UISegmentedControl* )sender{
- (void)slideModeChanged:(UISegmentedControl* )sender{
if(self->selectedWidgetView != nil && self->widgetViewSelected){
selectedWidgetView.isSlidable = _slidableSelector.selectedSegmentIndex == 0;
selectedWidgetView.slideMode = _slidableSelector.selectedSegmentIndex;
}
}
@@ -1065,7 +1065,7 @@
[self.mouseButtonDownSelector setTitleTextAttributes:whiteFontAttributes forState:UIControlStateNormal];
self.mouseDownButtonStack.hidden = YES;
[self.slidableSelector addTarget:self action:@selector(slidableChanged:) forControlEvents:(UIControlEventValueChanged)];
[self.slidableSelector addTarget:self action:@selector(slideModeChanged:) forControlEvents:(UIControlEventValueChanged)];
[self.slidableSelector setTitleTextAttributes:whiteFontAttributes forState:UIControlStateNormal];
self.slidableStack.hidden = YES;
+38 -8
View File
@@ -1052,43 +1052,73 @@
}
},
"cKS-fy-Zpg.segmentTitles[0]" : {
"comment" : "Class = \"UISegmentedControl\"; cKS-fy-Zpg.segmentTitles[0] = \"yes\"; ObjectID = \"cKS-fy-Zpg\";",
"comment" : "Class = \"UISegmentedControl\"; cKS-fy-Zpg.segmentTitles[0] = \"toggle\"; ObjectID = \"cKS-fy-Zpg\";",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "yes"
"value" : "toggle"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "开启"
"value" : "滑出时松开"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "開啟"
"value" : "滑出時鬆開"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "開啟"
"value" : "滑出時鬆開"
}
}
}
},
"cKS-fy-Zpg.segmentTitles[1]" : {
"comment" : "Class = \"UISegmentedControl\"; cKS-fy-Zpg.segmentTitles[1] = \"no\"; ObjectID = \"cKS-fy-Zpg\";",
"comment" : "Class = \"UISegmentedControl\"; cKS-fy-Zpg.segmentTitles[1] = \"slide & hold\"; ObjectID = \"cKS-fy-Zpg\";",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "no"
"value" : "slide & hold"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "滑动时按下"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "滑動時按下"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "滑動時按下"
}
}
}
},
"cKS-fy-Zpg.segmentTitles[2]" : {
"comment" : "Class = \"UISegmentedControl\"; cKS-fy-Zpg.segmentTitles[2] = \"disabled\"; ObjectID = \"cKS-fy-Zpg\";",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "disabled"
}
},
"zh-Hans" : {
@@ -1106,7 +1136,7 @@
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "關閉"
"value" : "關閉\n"
}
}
}