mirror of
https://github.com/coteditor/CotEditor.git
synced 2024-09-11 11:25:57 +03:00
Enable pinch-zoom in find panel fields
This commit is contained in:
parent
f2acabeace
commit
69ab0762ee
@ -5,6 +5,11 @@ Change Log
|
||||
3.6.2 (unreleased)
|
||||
--------------------------
|
||||
|
||||
### New Features
|
||||
|
||||
- Let the input fields in the find panel accept pinch-zoom.
|
||||
|
||||
|
||||
### Improvements
|
||||
|
||||
- Avoid selecting deleted spaces when undoing a soft tab deletion.
|
||||
|
@ -2,7 +2,6 @@
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="2Yd-sK-nho">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<development version="10000" identifier="xcode"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14313.18"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@ -66,7 +65,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="460" height="146"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<scrollView focusRingType="exterior" verticalHuggingPriority="249" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" minMagnification="1" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8gM-hc-HhV">
|
||||
<scrollView focusRingType="exterior" verticalHuggingPriority="249" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" allowsMagnification="YES" minMagnification="1" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8gM-hc-HhV" customClass="SynchronizedScrollView" customModule="CotEditor" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="82" width="420" height="44"/>
|
||||
<clipView key="contentView" id="vCs-g9-nGi" customClass="FindPanelTextClipView" customModule="CotEditor" customModuleProvider="target">
|
||||
<rect key="frame" x="1" y="1" width="418" height="42"/>
|
||||
@ -111,7 +110,7 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
<scrollView focusRingType="exterior" verticalHuggingPriority="249" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" minMagnification="1" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AIf-o5-KHg">
|
||||
<scrollView focusRingType="exterior" verticalHuggingPriority="249" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" allowsMagnification="YES" minMagnification="1" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AIf-o5-KHg" customClass="SynchronizedScrollView" customModule="CotEditor" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="28" width="420" height="44"/>
|
||||
<clipView key="contentView" id="vJP-0z-fPc" customClass="FindPanelTextClipView" customModule="CotEditor" customModuleProvider="target">
|
||||
<rect key="frame" x="1" y="1" width="418" height="42"/>
|
||||
|
@ -102,6 +102,8 @@
|
||||
2A18A5BF1C4A746A00BAD817 /* Encodings in Resources */ = {isa = PBXBuildFile; fileRef = 2A18A5BE1C4A746A00BAD817 /* Encodings */; };
|
||||
2A1A8AFA207081D9004DFEBB /* InvisibleFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1A8AF9207081D9004DFEBB /* InvisibleFormatter.swift */; };
|
||||
2A1A8AFB207081D9004DFEBB /* InvisibleFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1A8AF9207081D9004DFEBB /* InvisibleFormatter.swift */; };
|
||||
2A1B7E75216CBBEA002C7395 /* SynchronizedScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1B7E74216CBBEA002C7395 /* SynchronizedScrollView.swift */; };
|
||||
2A1B7E76216CBBEA002C7395 /* SynchronizedScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1B7E74216CBBEA002C7395 /* SynchronizedScrollView.swift */; };
|
||||
2A1CD5541DD1AADE006E17DB /* NSAlert+ModalSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1CD5531DD1AADE006E17DB /* NSAlert+ModalSheet.swift */; };
|
||||
2A1CD5551DD1AADE006E17DB /* NSAlert+ModalSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1CD5531DD1AADE006E17DB /* NSAlert+ModalSheet.swift */; };
|
||||
2A1EB5C419AD469500C1E37E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2A1EB5C319AD469500C1E37E /* Assets.xcassets */; };
|
||||
@ -851,6 +853,7 @@
|
||||
2A18A5BC1C4A730D00BAD817 /* EncodingDetectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EncodingDetectionTests.swift; sourceTree = "<group>"; };
|
||||
2A18A5BE1C4A746A00BAD817 /* Encodings */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Encodings; path = TestFiles/Encodings; sourceTree = "<group>"; };
|
||||
2A1A8AF9207081D9004DFEBB /* InvisibleFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvisibleFormatter.swift; sourceTree = "<group>"; };
|
||||
2A1B7E74216CBBEA002C7395 /* SynchronizedScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SynchronizedScrollView.swift; sourceTree = "<group>"; };
|
||||
2A1CD5531DD1AADE006E17DB /* NSAlert+ModalSheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAlert+ModalSheet.swift"; sourceTree = "<group>"; };
|
||||
2A1EB5C319AD469500C1E37E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
2A1FAD5720A74D0A00566D7C /* MutableCopying.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutableCopying.swift; sourceTree = "<group>"; };
|
||||
@ -1409,6 +1412,7 @@
|
||||
2A5D132E1D1FACC900D38E6A /* FindPanelLayoutManager.swift */,
|
||||
2A4AF76620759BE500C47606 /* RegexFindPanelTextView.swift */,
|
||||
2A0778602072040500876277 /* RegularExpressionSyntaxType.swift */,
|
||||
2A1B7E74216CBBEA002C7395 /* SynchronizedScrollView.swift */,
|
||||
);
|
||||
name = "Text View";
|
||||
sourceTree = "<group>";
|
||||
@ -2837,6 +2841,7 @@
|
||||
2A78BFA01D1AF82A00A583D2 /* IntegrationPaneController.swift in Sources */,
|
||||
2AA375441D403F100080C27C /* String+Encoding.swift in Sources */,
|
||||
2A1FAD5920A74D0A00566D7C /* MutableCopying.swift in Sources */,
|
||||
2A1B7E76216CBBEA002C7395 /* SynchronizedScrollView.swift in Sources */,
|
||||
2A6FD9DE1D392EFF00A59784 /* ATSTypesetter.swift in Sources */,
|
||||
2A5D13491D1FEF9900D38E6A /* FindPanelFieldViewController.swift in Sources */,
|
||||
2ACC5E421E7B08D300109ABC /* MultipleReplacementViewController.swift in Sources */,
|
||||
@ -3073,6 +3078,7 @@
|
||||
2A8C338F1D3E1C040005B0B7 /* IncompatibleCharacter.swift in Sources */,
|
||||
2A9BF3C41D382BB100E3D3E2 /* EditorTextView+Transformation.swift in Sources */,
|
||||
2A3A922B205638A600F9B5F3 /* BackgroundView.swift in Sources */,
|
||||
2A1B7E75216CBBEA002C7395 /* SynchronizedScrollView.swift in Sources */,
|
||||
2A42579E1D229A8B0086DAAD /* OutlineParseOperation.swift in Sources */,
|
||||
2AE73F3D2039A29300D8903B /* URL+ExtendedAttribute.swift in Sources */,
|
||||
2A0DD6331E655C4A001CAAA3 /* TokenTextView.swift in Sources */,
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
final class FindPanelFieldViewController: NSViewController, NSTextViewDelegate, NSUserInterfaceValidations {
|
||||
final class FindPanelFieldViewController: NSViewController, NSTextViewDelegate {
|
||||
|
||||
// MARK: Private Properties
|
||||
|
||||
@ -128,54 +128,6 @@ final class FindPanelFieldViewController: NSViewController, NSTextViewDelegate,
|
||||
|
||||
// MARK: Action Messages
|
||||
|
||||
func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
|
||||
|
||||
guard let action = item.action else { return false }
|
||||
|
||||
switch action {
|
||||
case #selector(smallerFont):
|
||||
guard let scrollView = self.findTextView?.enclosingScrollView else { return false }
|
||||
return scrollView.magnification > scrollView.minMagnification
|
||||
|
||||
case #selector(biggerFont):
|
||||
guard let scrollView = self.findTextView?.enclosingScrollView else { return false }
|
||||
return scrollView.magnification < scrollView.maxMagnification
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
/// scale up
|
||||
@IBAction func biggerFont(_ sender: Any?) {
|
||||
|
||||
for textView in [self.findTextView, self.replacementTextView] {
|
||||
textView?.enclosingScrollView?.animator().magnification += 0.2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// scale down
|
||||
@IBAction func smallerFont(_ sender: Any?) {
|
||||
|
||||
for textView in [self.findTextView, self.replacementTextView] {
|
||||
textView?.enclosingScrollView?.animator().magnification -= 0.2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// reset scale and font to default
|
||||
@IBAction func resetFont(_ sender: Any?) {
|
||||
|
||||
for textView in [self.findTextView, self.replacementTextView] {
|
||||
textView?.enclosingScrollView?.animator().magnification = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// show regular expression reference as popover
|
||||
@IBAction func showRegexHelp(_ sender: Any?) {
|
||||
|
||||
|
120
CotEditor/Sources/SynchronizedScrollView.swift
Normal file
120
CotEditor/Sources/SynchronizedScrollView.swift
Normal file
@ -0,0 +1,120 @@
|
||||
//
|
||||
// SynchronizedScrollView.swift
|
||||
//
|
||||
// CotEditor
|
||||
// https://coteditor.com
|
||||
//
|
||||
// Created by 1024jp on 2018-10-09.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2018 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
final class SynchronizedScrollView: NSScrollView {
|
||||
|
||||
// MARK: Scroll View Methods
|
||||
|
||||
/// receive pinch zoom event
|
||||
override func magnify(with event: NSEvent) {
|
||||
|
||||
let magnification = self.magnification + event.magnification
|
||||
let location = self.contentView.convert(event.locationInWindow, from: nil)
|
||||
|
||||
for scrollView in self.siblings {
|
||||
scrollView.setMagnification(magnification, centeredAt: location)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// receive double-tap event adjusting scale
|
||||
override func smartMagnify(with event: NSEvent) {
|
||||
|
||||
for scrollView in self.siblings {
|
||||
scrollView.syncedSmartMagnify(with: event)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: Private Methods
|
||||
|
||||
/// auto-founded scroll views to sync (including the receiver itself)
|
||||
private var siblings: [SynchronizedScrollView] {
|
||||
|
||||
return self.superview?.subviews.compactMap { $0 as? SynchronizedScrollView } ?? [self]
|
||||
}
|
||||
|
||||
|
||||
/// invoking super's `smartMagnify(with:)` without the issue about the cycle invoking
|
||||
private func syncedSmartMagnify(with event: NSEvent) {
|
||||
|
||||
super.smartMagnify(with: event)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: Actions
|
||||
|
||||
extension SynchronizedScrollView: NSUserInterfaceValidations {
|
||||
|
||||
func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
|
||||
|
||||
guard let action = item.action else { return false }
|
||||
|
||||
switch action {
|
||||
case #selector(smallerFont):
|
||||
return self.magnification > self.minMagnification
|
||||
|
||||
case #selector(biggerFont):
|
||||
return self.magnification < self.maxMagnification
|
||||
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// scale up
|
||||
@IBAction func biggerFont(_ sender: Any?) {
|
||||
|
||||
for scrollView in self.siblings {
|
||||
scrollView.animator().magnification += 0.2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// scale down
|
||||
@IBAction func smallerFont(_ sender: Any?) {
|
||||
|
||||
for scrollView in self.siblings {
|
||||
scrollView.animator().magnification -= 0.2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// reset scale to default
|
||||
@IBAction func resetFont(_ sender: Any?) {
|
||||
|
||||
for scrollView in self.siblings {
|
||||
scrollView.animator().magnification = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user