diff --git a/bin/mac/libnst64.dylib b/bin/mac/libnst64.dylib index 597c2e6db6c0..c1f675e8e9f9 100755 Binary files a/bin/mac/libnst64.dylib and b/bin/mac/libnst64.dylib differ diff --git a/native/MacTouchBar/src/Button.m b/native/MacTouchBar/src/Button.m index 06a59f54345e..9bdb04cf9556 100644 --- a/native/MacTouchBar/src/Button.m +++ b/native/MacTouchBar/src/Button.m @@ -74,6 +74,20 @@ const NSSize g_defaultMinSize = {72, 30}; // empiric value // // [NSGraphicsContext restoreGraphicsState]; //} +//- (void)drawDebugRect:(NSRect)frame color:(NSColor *)col { +// // NSLog(@"drawDebugRect: %@", NSStringFromRect(frame)); +// +// [[NSGraphicsContext currentContext] saveGraphicsState]; +// +// if (col == nil) +// col = [NSColor colorWithRed:105/255.0 green:211/255.0 blue:232/255.0 alpha:1.0]; +// [col set]; +// [col setStroke]; +// [col setFill]; +// NSFrameRect(frame); +// +// [NSGraphicsContext restoreGraphicsState]; +//} - (NSSize)cellSizeForBounds:(NSRect)rect { if (self.title == nil) { // NSLog(@"\t empty text, use default size %@", NSStringFromSize(g_defaultMinSize)); @@ -90,43 +104,56 @@ const NSSize g_defaultMinSize = {72, 30}; // empiric value } - (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView *)controlView { // NSLog(@"drawInteriorWithFrame: %@", NSStringFromRect(frame)); - if (self.image == nil) { - [super drawTitle:self.attributedTitle withFrame:frame inView:controlView]; - return; - } - - if (self.title == nil) { + if (self.title == nil || self.title.length <= 0) { [super drawImage:self.image withFrame:frame inView:controlView]; return; } - const CGFloat imgW = self.image.size.width; + const CGFloat imgW = self.image == nil ? 0 : self.image.size.width; + const CGFloat imgWithMargin = imgW > 0 ? self.myMargin + imgW : 0; + NSSize txtSize = [self.title sizeWithAttributes:@{ NSFontAttributeName:self.font }]; const CGFloat txtW = txtSize.width; - const CGFloat fullW = self.myBorder*2 + txtW + self.myMargin + imgW; + const CGFloat fullW = self.myBorder*2 + txtW + imgWithMargin; NSRect rcImg = frame; + rcImg.size.width = imgW; NSRect rcTxt = frame; if (fullW <= frame.size.width) { const CGFloat delta = frame.size.width - fullW; - rcImg.origin.x = delta/2 + self.myBorder; - rcImg.size.width = imgW; - rcTxt.origin.x = rcImg.origin.x + imgW + self.myMargin; - rcTxt.size.width = txtW + self.myBorder; + if (imgW > 0) { + rcImg.origin.x = delta/2 + self.myBorder; + rcTxt.origin.x = rcImg.origin.x + imgWithMargin; + rcTxt.size.width = txtW + 1; + } else { + rcTxt.origin.x = delta/2 + self.myBorder; + rcTxt.size.width = txtW + 1; + } } else { - rcImg.origin.x = self.myBorder; - rcImg.size.width = imgW; - rcTxt.origin.x = rcImg.origin.x + imgW + self.myMargin; - rcTxt.size.width = frame.size.width - self.myBorder - rcTxt.origin.x; + if (imgW > 0) { + rcImg.origin.x = self.myBorder; + rcTxt.origin.x = rcImg.origin.x + imgWithMargin; + rcTxt.size.width = frame.size.width - self.myBorder - rcTxt.origin.x; + } else { + rcTxt.origin.x = self.myBorder; + rcTxt.size.width = frame.size.width - self.myBorder*2; + } } - if (rcImg.size.width > 0) + if (imgW > 0) { [super drawImage:self.image withFrame:rcImg inView:controlView]; - if (rcTxt.size.width > 0) +// NSColor * col = [NSColor colorWithRed:105/255.0 green:211/255.0 blue:0/255.0 alpha:1.0]; +// [self drawDebugRect:rcImg color:col]; + } + if (rcTxt.size.width > 0) { [super drawTitle:self.attributedTitle withFrame:rcTxt inView:controlView]; +// NSColor * col = [NSColor colorWithRed:105/255.0 green:0/255.0 blue:255/255.0 alpha:1.0]; +// [self drawDebugRect:rcTxt color:col]; + } +// [self drawDebugRect:frame color:nil]; } @end -const int BUTTON_UPDATE_WIDTH = 1; +const int BUTTON_UPDATE_LAYOUT = 1; const int BUTTON_UPDATE_FLAGS = 1 << 1; const int BUTTON_UPDATE_TEXT = 1 << 2; const int BUTTON_UPDATE_IMG = 1 << 3; @@ -138,14 +165,35 @@ const int BUTTON_FLAG_SELECTED = 1 << 1; const int BUTTON_FLAG_COLORED = 1 << 2; const int BUTTON_FLAG_TOGGLE = 1 << 3; -const int BUTTON_PRIORITY_SHIFT = 3*8; -const unsigned int BUTTON_PRIORITY_MASK = 0xFF << BUTTON_PRIORITY_SHIFT; +const unsigned int LAYOUT_WIDTH_MASK = 0x0FFF; +const unsigned int LAYOUT_FLAG_MIN_WIDTH = 1 << 15; +const unsigned int LAYOUT_FLAG_MAX_WIDTH = 1 << 14; + +const unsigned int LAYOUT_MARGIN_SHIFT = 2*8; +const unsigned int LAYOUT_MARGIN_MASK = 0xFF << LAYOUT_MARGIN_SHIFT; +const unsigned int LAYOUT_BORDER_SHIFT = 3*8; +const unsigned int LAYOUT_BORDER_MASK = 0xFF << LAYOUT_BORDER_SHIFT; + +const int BUTTON_PRIORITY_SHIFT = 3*8; +const unsigned int BUTTON_PRIORITY_MASK = 0xFF << BUTTON_PRIORITY_SHIFT; static int _getPriority(int flags) { return (flags & BUTTON_PRIORITY_MASK) >> BUTTON_PRIORITY_SHIFT; } -static void _setButtonData(NSButtonJAction *button, int updateOptions, int buttonWidth, int buttonFlags, NSString *nstext, NSImage *img, execute jaction) { +static int _getWidth(int layoutBits) { + return (layoutBits & LAYOUT_WIDTH_MASK); +} + +static int _getMargin(int layoutBits) { + return (layoutBits & LAYOUT_MARGIN_MASK) >> LAYOUT_MARGIN_SHIFT; +} + +static int _getBorder(int layoutBits) { + return (layoutBits & LAYOUT_BORDER_MASK) >> LAYOUT_BORDER_SHIFT; +} + +static void _setButtonData(NSButtonJAction *button, int updateOptions, int layoutBits, int buttonFlags, NSString *nstext, NSImage *img, execute jaction) { if (updateOptions & BUTTON_UPDATE_ACTION) { button.jaction = jaction; if (jaction) { @@ -169,12 +217,36 @@ static void _setButtonData(NSButtonJAction *button, int updateOptions, int butto if (updateOptions & BUTTON_UPDATE_IMG) [button setImage:img]; - if (updateOptions & BUTTON_UPDATE_WIDTH) { - button.bwidth = buttonWidth; - if (button.bwidth > 0.1f) - [button.widthAnchor constraintEqualToConstant:button.bwidth].active = YES; - else + if (updateOptions & BUTTON_UPDATE_LAYOUT) { + const int width = _getWidth(layoutBits); + button.bwidth = width; + if (width > 0) { + bool isMinWidth = (layoutBits & LAYOUT_FLAG_MIN_WIDTH) != 0; + bool isMaxWidth = (layoutBits & LAYOUT_FLAG_MAX_WIDTH) != 0; + if (isMinWidth && isMaxWidth) { + nserror(@"invalid arguments specified: both min and max bits are 1"); + } + if (isMinWidth) { + //NSLog(@"set min width %d", width); + [button.widthAnchor constraintGreaterThanOrEqualToConstant:button.bwidth].active = YES; + } else if (isMaxWidth) { + //NSLog(@"set max width %d", width); + [button.widthAnchor constraintLessThanOrEqualToConstant:button.bwidth].active = YES; + } else { + //NSLog(@"set const width %d", width); + [button.widthAnchor constraintEqualToConstant:button.bwidth].active = YES; + } + } else [button.widthAnchor constraintEqualToAnchor:button.widthAnchor].active = NO; + + { // process margins + const int margin = _getMargin(layoutBits); + const int border = _getBorder(layoutBits); + if (margin > 0 || border > 0) { + [button setMargins:margin border:border]; + //NSLog(@"set insets: m=%d b=%d", margin, border); + } + } } if (updateOptions & BUTTON_UPDATE_FLAGS) { @@ -224,7 +296,7 @@ static void _setButtonData(NSButtonJAction *button, int updateOptions, int butto // NOTE: called from AppKit-thread (creation when TB becomes visible), uses default autorelease-pool (create before event processing) id createButton( const char *uid, - int buttonWidth, + int layoutBits, int buttonFlags, const char *text, const char *raster4ByteRGBA, int w, int h, @@ -238,7 +310,7 @@ id createButton( NSImage *img = createImgFrom4ByteRGBA((const unsigned char *) raster4ByteRGBA, w, h); NSString *nstext = createStringFromUTF8(text); - _setButtonData(button, BUTTON_UPDATE_ALL, buttonWidth, buttonFlags, nstext, img, jaction); + _setButtonData(button, BUTTON_UPDATE_ALL, layoutBits, buttonFlags, nstext, img, jaction); customItemForButton.view = button; // NOTE: view is strong const int prio = _getPriority(buttonFlags); @@ -254,7 +326,7 @@ id createButton( void updateButton( id buttObj, int updateOptions, - int buttonWidth, + int layoutBits, int buttonFlags, const char *text, const char *raster4ByteRGBA, int w, int h, @@ -269,13 +341,13 @@ void updateButton( if ([NSThread isMainThread]) { nstrace(@"sync update button [%@] (main thread: %@)", container.identifier, [NSThread currentThread]); - _setButtonData(button, updateOptions, buttonWidth, buttonFlags, nstext, img, jaction); + _setButtonData(button, updateOptions, layoutBits, buttonFlags, nstext, img, jaction); } else { nstrace(@"async update button [%@] (thread: %@)", container.identifier, [NSThread currentThread]); dispatch_async(dispatch_get_main_queue(), ^{ // NOTE: block is copied, img/text objects is automatically retained // nstrace(@"\tperform update button [%@] (thread: %@)", container.identifier, [NSThread currentThread]); - _setButtonData(button, updateOptions, buttonWidth, buttonFlags, nstext, img, jaction); + _setButtonData(button, updateOptions, layoutBits, buttonFlags, nstext, img, jaction); }); } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java index 905514a03ce4..c9bff7c200a9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java @@ -26,6 +26,7 @@ import com.intellij.openapi.actionSystem.ex.QuickList; import com.intellij.openapi.actionSystem.ex.QuickListsManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.keymap.KeyMapBundle; import com.intellij.openapi.keymap.KeyboardSettingsExternalizable; import com.intellij.openapi.keymap.Keymap; @@ -228,7 +229,8 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi } }); panel.add(myShowFnCheckbox, BorderLayout.SOUTH); - } + } else + Logger.getInstance(KeymapPanel.class).error("can't obtain application id from NSBundle"); } return panel; diff --git a/platform/platform-impl/src/com/intellij/ui/mac/touchbar/BuildUtils.java b/platform/platform-impl/src/com/intellij/ui/mac/touchbar/BuildUtils.java index 1b0c76378d98..ca524b2217c2 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/touchbar/BuildUtils.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/touchbar/BuildUtils.java @@ -44,6 +44,9 @@ class BuildUtils { private static final String ourFlexibleSeparatorText = "type.flexible"; private static final int ourRunConfigurationPopoverWidth = 143; + private static final int BUTTON_MIN_WIDTH_DLG = 107; + private static final int BUTTON_BORDER = 16; + private static final int BUTTON_IMAGE_MARGIN = 2; private static final String RUNNERS_GROUP_TOUCHBAR = "RunnerActionsTouchbar"; @@ -176,12 +179,14 @@ class BuildUtils { defIndex = c; continue; } - group.addButton().setText(DialogWrapper.extractMnemonic(sb).second).setThreadSafeAction(actions[c]); + final TBItemButton tbb = group.addButton().setText(DialogWrapper.extractMnemonic(sb).second).setThreadSafeAction(actions[c]); + _setDialogLayout(tbb); } - if (defIndex >= 0) - group.addButton().setText(DialogWrapper.extractMnemonic(buttons[defIndex]).second).setThreadSafeAction(actions[defIndex]) - .setColored(true); + if (defIndex >= 0) { + final TBItemButton tbb = group.addButton().setText(DialogWrapper.extractMnemonic(buttons[defIndex]).second).setThreadSafeAction(actions[defIndex]).setColored(true); + _setDialogLayout(tbb); + } result.setPrincipal(gr); result.selectVisibleItemsToShow(); @@ -207,7 +212,8 @@ class BuildUtils { continue; // NOTE: must set different priorities for items, otherwise system can hide all items with the same priority (but some of them is able to be placed) - result.addAnActionButton(anAct, TBItemAnActionButton.SHOWMODE_TEXT_ONLY, ms).setComponent(ob).setPriority(--prio); + final TBItemButton tbb = result.addAnActionButton(anAct, TBItemAnActionButton.SHOWMODE_TEXT_ONLY, ms).setComponent(ob).setPriority(--prio); + _setDialogLayout(tbb); } } } @@ -226,13 +232,16 @@ class BuildUtils { final AnAction anAct = _createAnAction(jb.getAction(), jb, false); if (anAct == null) continue; - group.addAnActionButton(anAct, TBItemAnActionButton.SHOWMODE_TEXT_ONLY, ms).setComponent(jb); + final TBItemButton tbb = group.addAnActionButton(anAct, TBItemAnActionButton.SHOWMODE_TEXT_ONLY, ms).setComponent(jb); + _setDialogLayout(tbb); } if (jbdef != null) { final AnAction anAct = _createAnAction(jbdef.getAction(), jbdef, false); - if (anAct != null) - group.addAnActionButton(anAct, TBItemAnActionButton.SHOWMODE_TEXT_ONLY, ms).setComponent(jbdef).setColored(true); + if (anAct != null) { + final TBItemButton tbb = group.addAnActionButton(anAct, TBItemAnActionButton.SHOWMODE_TEXT_ONLY, ms).setComponent(jbdef).setColored(true); + _setDialogLayout(tbb); + } } result.selectVisibleItemsToShow(); @@ -283,6 +292,12 @@ class BuildUtils { return tb; } + private static void _setDialogLayout(TBItemButton button) { + if (button == null) + return; + button.setLayout(BUTTON_MIN_WIDTH_DLG, NSTLibrary.LAYOUT_FLAG_MIN_WIDTH, BUTTON_IMAGE_MARGIN, BUTTON_BORDER); + } + interface INodeFilter { boolean skip(String nodeId); } diff --git a/platform/platform-impl/src/com/intellij/ui/mac/touchbar/NSTLibrary.java b/platform/platform-impl/src/com/intellij/ui/mac/touchbar/NSTLibrary.java index b570440bc5be..bdf87058ea54 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/touchbar/NSTLibrary.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/touchbar/NSTLibrary.java @@ -47,7 +47,7 @@ public interface NSTLibrary extends Library { ID createScrubber(String uid, int itemWidth, ScrubberItemData[] items, int count); ID createGroupItem(String uid, ID[] items, int count); - int BUTTON_UPDATE_WIDTH = 1; + int BUTTON_UPDATE_LAYOUT = 1; int BUTTON_UPDATE_FLAGS = 1 << 1; int BUTTON_UPDATE_TEXT = 1 << 2; int BUTTON_UPDATE_IMG = 1 << 3; @@ -59,6 +59,14 @@ public interface NSTLibrary extends Library { int BUTTON_FLAG_COLORED = 1 << 2; int BUTTON_FLAG_TOGGLE = 1 << 3; + int LAYOUT_WIDTH_MASK = 0x0FFF; + int LAYOUT_FLAG_MIN_WIDTH = 1 << 15; + int LAYOUT_FLAG_MAX_WIDTH = 1 << 14; + int LAYOUT_MARGIN_SHIFT = 2*8; + int LAYOUT_MARGIN_MASK = 0xFF << LAYOUT_MARGIN_SHIFT; + int LAYOUT_BORDER_SHIFT = 3*8; + int LAYOUT_BORDER_MASK = 0xFF << LAYOUT_BORDER_SHIFT; + int BUTTON_PRIORITY_SHIFT = 3*8; int BUTTON_PRIORITY_MASK = 0xFF << BUTTON_PRIORITY_SHIFT; @@ -69,4 +77,6 @@ public interface NSTLibrary extends Library { void updateScrubber(ID scrubObj, int itemWidth, ScrubberItemData[] items, int count); static int priority2mask(byte prio) { return (prio + 128) << BUTTON_PRIORITY_SHIFT; } + static int margin2mask(byte margin) { return ((int)margin & 0xFF) << LAYOUT_MARGIN_SHIFT; } + static int border2mask(byte border) { return ((int)border & 0xFF) << LAYOUT_BORDER_SHIFT; } } diff --git a/platform/platform-impl/src/com/intellij/ui/mac/touchbar/TBItemButton.java b/platform/platform-impl/src/com/intellij/ui/mac/touchbar/TBItemButton.java index a87f7b8afd7a..fe5cb49044d6 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/touchbar/TBItemButton.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/touchbar/TBItemButton.java @@ -14,7 +14,7 @@ import javax.swing.*; class TBItemButton extends TBItem { protected @Nullable Icon myIcon; protected @Nullable String myText; - protected int myWidth = -1; + protected int myLayoutBits = 0; protected int myFlags = 0; private @Nullable Runnable myAction; @@ -83,12 +83,24 @@ class TBItemButton extends TBItem { return this; } + TBItemButton setWidth(int width) { return setLayout(width, 0, 2, 8); } - TBItemButton setWidth(int width) { - if (width != myWidth) { - myWidth = width; + TBItemButton setLayout(int width, int widthFlags, int margin, int border) { + if (width < 0) + width = 0; + if (margin < 0) + margin = 0; + if (border < 0) + border = 0; + + int newLayout = width & NSTLibrary.LAYOUT_WIDTH_MASK; + newLayout |= widthFlags; + newLayout |= NSTLibrary.margin2mask((byte)margin); + newLayout |= NSTLibrary.border2mask((byte)border); + if (myLayoutBits != newLayout) { + myLayoutBits = newLayout; if (myNativePeer != ID.NIL) { - myUpdateOptions |= NSTLibrary.BUTTON_UPDATE_WIDTH; + myUpdateOptions |= NSTLibrary.BUTTON_UPDATE_LAYOUT; _updateNativePeer(); } } @@ -141,7 +153,7 @@ class TBItemButton extends TBItem { int flags = _applyFlag(myFlags, isSelected, NSTLibrary.BUTTON_FLAG_SELECTED); flags = _applyFlag(flags, isDisabled, NSTLibrary.BUTTON_FLAG_DISABLED); - _update(icon, text, myAction, myWidth, flags); + _update(icon, text, myAction, flags); } private static boolean _equals(Icon ic0, Icon ic1) { @@ -150,7 +162,7 @@ class TBItemButton extends TBItem { return ic0 != null ? ic0.equals(ic1) : ic1.equals(ic0); } - synchronized private void _update(Icon icon, String text, Runnable action, int buttWidth, int buttFlags) { + synchronized private void _update(Icon icon, String text, Runnable action, int buttFlags) { if (myNativePeer != ID.NIL) { if (!_equals(icon, myIcon)) { // NOTE: some of layered buttons (like 'stop' or 'debug') can change the icon-object permanently (every second) without any visible differences @@ -161,15 +173,12 @@ class TBItemButton extends TBItem { myUpdateOptions |= NSTLibrary.BUTTON_UPDATE_TEXT; if (action != myAction) myUpdateOptions |= NSTLibrary.BUTTON_UPDATE_ACTION; - if (buttWidth != myWidth) - myUpdateOptions |= NSTLibrary.BUTTON_UPDATE_WIDTH; if (buttFlags != myFlags) myUpdateOptions |= NSTLibrary.BUTTON_UPDATE_FLAGS; } myIcon = icon; myText = text; myAction = action; - myWidth = buttWidth; myFlags = buttFlags; if (myUpdateOptions != 0) updateNativePeer(); @@ -182,14 +191,14 @@ class TBItemButton extends TBItem { final NSTLibrary.Action callback = (myUpdateOptions & NSTLibrary.BUTTON_UPDATE_ACTION) != 0 ? myNativeCallback : null; // System.out.printf("_updateNativePeer, button [%s]: updateOptions 0x%X\n", myUid, myUpdateOptions); final int validFlags = _validateFlags(); - NST.updateButton(myNativePeer, myUpdateOptions, myWidth, validFlags, text, icon, callback); + NST.updateButton(myNativePeer, myUpdateOptions, myLayoutBits, validFlags, text, icon, callback); myUpdateOptions = 0; } @Override synchronized protected ID _createNativePeer() { // System.out.printf("_createNativePeer, button [%s]\n", myUid); - return NST.createButton(myUid, myWidth, _validateFlags(), myText, myIcon, myNativeCallback); + return NST.createButton(myUid, myLayoutBits, _validateFlags(), myText, myIcon, myNativeCallback); } private int _validateFlags() {