mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-242733 Updated NLS for intellij.emojipicker & reformatted code
GitOrigin-RevId: 11b8c76106b0dbd522ac7e033a57af3589cae830
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b57b618162
commit
99e0303b4a
@@ -0,0 +1,13 @@
|
||||
# Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
# These properties are accessed dynamically, so suppress "unused" warnings
|
||||
# suppress inspection "UnusedProperty" for whole file
|
||||
|
||||
category.EmojiPicker.RecentlyUsed=Recently Used
|
||||
category.EmojiPicker.SmileysAndPeople=Smileys \\& People
|
||||
category.EmojiPicker.AnimalsAndNature=Animals \\& Nature
|
||||
category.EmojiPicker.FoodAndDrink=Food \\& Drink
|
||||
category.EmojiPicker.TravelAndPlaces=Travel \\& Places
|
||||
category.EmojiPicker.Activities=Activities
|
||||
category.EmojiPicker.Objects=Objects
|
||||
category.EmojiPicker.Symbols=Symbols
|
||||
category.EmojiPicker.Flags=Flags
|
||||
@@ -1,16 +1,8 @@
|
||||
# Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
action.EmojiPicker.Open.text=Emo_ji & Symbols
|
||||
|
||||
action.EmojiPicker.Open.text=Emo_ji \\& Symbols
|
||||
|
||||
message.EmojiPicker.Initializing=Initializing emoji picker
|
||||
message.EmojiPicker.BuildingIndex=Building search index
|
||||
message.EmojiPicker.SavingIndexData=Saving data
|
||||
|
||||
category.EmojiPicker.RecentlyUsed=Recently Used
|
||||
category.EmojiPicker.SmileysAndPeople=Smileys & People
|
||||
category.EmojiPicker.AnimalsAndNature=Animals & Nature
|
||||
category.EmojiPicker.FoodAndDrink=Food & Drink
|
||||
category.EmojiPicker.TravelAndPlaces=Travel & Places
|
||||
category.EmojiPicker.Activities=Activities
|
||||
category.EmojiPicker.Objects=Objects
|
||||
category.EmojiPicker.Symbols=Symbols
|
||||
category.EmojiPicker.Flags=Flags
|
||||
message.EmojiPicker.NoEmojiFound=No emoji found
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.emojipicker;
|
||||
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Emoji implements Serializable {
|
||||
|
||||
private final int myId;
|
||||
private final String myValue;
|
||||
@NonNls private final String myValue;
|
||||
private final boolean myToned;
|
||||
|
||||
public Emoji(int id, String value, boolean toned) {
|
||||
public Emoji(int id, @NonNls String value, boolean toned) {
|
||||
myId = id;
|
||||
myValue = value;
|
||||
myToned = toned;
|
||||
@@ -19,8 +21,8 @@ public class Emoji implements Serializable {
|
||||
return myId;
|
||||
}
|
||||
|
||||
@NlsSafe
|
||||
public String getTonedValue(EmojiSkinTone tone) {
|
||||
return myToned ? myValue + tone.getStringValue() : myValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package org.jetbrains.plugins.emojipicker;
|
||||
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.Serializable;
|
||||
@@ -9,9 +10,7 @@ import java.util.List;
|
||||
|
||||
|
||||
public class EmojiCategory implements Serializable {
|
||||
|
||||
|
||||
private final String myId;
|
||||
@NonNls private final String myId;
|
||||
private final List<Emoji> myEmoji;
|
||||
private transient Icon myIcon;
|
||||
|
||||
@@ -20,6 +19,7 @@ public class EmojiCategory implements Serializable {
|
||||
myEmoji = emojiList;
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public String getId() {
|
||||
return myId;
|
||||
}
|
||||
@@ -30,11 +30,9 @@ public class EmojiCategory implements Serializable {
|
||||
|
||||
public Icon getIcon() {
|
||||
Icon icon = myIcon;
|
||||
if(icon == null) {
|
||||
if (icon == null) {
|
||||
myIcon = icon = IconLoader.getIcon("/icons/categories/" + myId + ".svg", EmojiCategory.class);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.emojipicker;
|
||||
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class EmojiSearchIndex implements Serializable {
|
||||
|
||||
|
||||
private final String myChars;
|
||||
@NonNls private final String myChars;
|
||||
private final int[] myData;
|
||||
private final int myRootNodeOffset, myTotalEmojiIndices;
|
||||
|
||||
private EmojiSearchIndex(String chars, int[] data, int rootNodeOffset, int totalEmojiIndices) {
|
||||
private EmojiSearchIndex(@NonNls String chars, int[] data, int rootNodeOffset, int totalEmojiIndices) {
|
||||
myChars = chars;
|
||||
myData = data;
|
||||
myRootNodeOffset = rootNodeOffset;
|
||||
myTotalEmojiIndices = totalEmojiIndices;
|
||||
}
|
||||
|
||||
private int findNodeForPrefix(String key, int prefixOffset, int nodeOffset) {
|
||||
if(prefixOffset == key.length()) return nodeOffset;
|
||||
private int findNodeForPrefix(@NonNls String key, int prefixOffset, int nodeOffset) {
|
||||
if (prefixOffset == key.length()) return nodeOffset;
|
||||
int children = myData[nodeOffset + 2];
|
||||
for (int c = 0; c < children; c++) {
|
||||
int child = myData[nodeOffset + 3 + c];
|
||||
int childCharsFrom = myData[child], childCharsTo = myData[child + 1];
|
||||
int i, limit = Math.min(key.length() - prefixOffset, childCharsTo - childCharsFrom);
|
||||
int i, limit = Math.min(key.length() - prefixOffset, childCharsTo - childCharsFrom);
|
||||
for (i = 0; i < limit; i++) {
|
||||
if(key.charAt(prefixOffset + i) != myChars.charAt(childCharsFrom + i)) break;
|
||||
if (key.charAt(prefixOffset + i) != myChars.charAt(childCharsFrom + i)) break;
|
||||
}
|
||||
if(i == childCharsTo - childCharsFrom) return findNodeForPrefix(key, prefixOffset + i, child);
|
||||
if(i == key.length() - prefixOffset) return child;
|
||||
if(i > 0) return -1;
|
||||
if (i == childCharsTo - childCharsFrom) return findNodeForPrefix(key, prefixOffset + i, child);
|
||||
if (i == key.length() - prefixOffset) return child;
|
||||
if (i > 0) return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -50,13 +50,13 @@ public class EmojiSearchIndex implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean lookupIds(boolean[] idMap, String prefix) {
|
||||
if(idMap.length < myTotalEmojiIndices) {
|
||||
public boolean lookupIds(boolean[] idMap, @NonNls String prefix) {
|
||||
if (idMap.length < myTotalEmojiIndices) {
|
||||
throw new IllegalArgumentException("Output array is too small: " + idMap.length +
|
||||
", but there are " + myTotalEmojiIndices + "emoji indices");
|
||||
}
|
||||
int node = findNodeForPrefix(prefix, 0, myRootNodeOffset);
|
||||
if(node == -1) return false;
|
||||
if (node == -1) return false;
|
||||
Arrays.fill(idMap, false);
|
||||
collectIdsFromSubtree(idMap, node);
|
||||
return true;
|
||||
@@ -67,34 +67,32 @@ public class EmojiSearchIndex implements Serializable {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static class PrefixTree {
|
||||
|
||||
private String myPrefix;
|
||||
@NonNls private String myPrefix;
|
||||
private final List<PrefixTree> myChildren = new ArrayList<>();
|
||||
private final List<Integer> myValues = new ArrayList<>();
|
||||
|
||||
private PrefixTree(String prefix) { myPrefix = prefix; }
|
||||
private PrefixTree(@NonNls String prefix) { myPrefix = prefix; }
|
||||
|
||||
public PrefixTree() { this(""); }
|
||||
|
||||
public void add(String key, int value) {
|
||||
if(key.isEmpty()) {
|
||||
public void add(@NonNls String key, int value) {
|
||||
if (key.isEmpty()) {
|
||||
myValues.add(value);
|
||||
return;
|
||||
}
|
||||
for(int c = 0; c < myChildren.size(); c++) {
|
||||
for (int c = 0; c < myChildren.size(); c++) {
|
||||
PrefixTree child = myChildren.get(c);
|
||||
int i, limit = Math.min(key.length(), child.myPrefix.length());
|
||||
int i, limit = Math.min(key.length(), child.myPrefix.length());
|
||||
for (i = 0; i < limit; i++) {
|
||||
if(key.charAt(i) != child.myPrefix.charAt(i)) break;
|
||||
if (key.charAt(i) != child.myPrefix.charAt(i)) break;
|
||||
}
|
||||
if(i == child.myPrefix.length()) {
|
||||
if (i == child.myPrefix.length()) {
|
||||
child.add(key.substring(limit), value);
|
||||
return;
|
||||
}
|
||||
else if(i > 0) {
|
||||
else if (i > 0) {
|
||||
PrefixTree
|
||||
firstPart = new PrefixTree(key.substring(0, i));
|
||||
child.myPrefix = child.myPrefix.substring(i);
|
||||
@@ -128,8 +126,8 @@ public class EmojiSearchIndex implements Serializable {
|
||||
System.arraycopy(childrenLinks, 0, data.myData, data.myDataPointer, childrenLinks.length);
|
||||
data.myDataPointer += childrenLinks.length;
|
||||
data.write(myValues.size());
|
||||
for(int i : myValues) {
|
||||
if(i > data.myMaxEmojiId) data.myMaxEmojiId = i;
|
||||
for (int i : myValues) {
|
||||
if (i > data.myMaxEmojiId) data.myMaxEmojiId = i;
|
||||
data.write(i);
|
||||
}
|
||||
return index;
|
||||
@@ -139,15 +137,15 @@ public class EmojiSearchIndex implements Serializable {
|
||||
StringBuffer myChars;
|
||||
int[] myData;
|
||||
int myDataPointer, myMaxEmojiId = -1;
|
||||
|
||||
private void ensureDataCapacity(int remaining) {
|
||||
if(myDataPointer + remaining > myData.length) myData = Arrays.copyOf(myData, myData.length * 2);
|
||||
if (myDataPointer + remaining > myData.length) myData = Arrays.copyOf(myData, myData.length * 2);
|
||||
}
|
||||
|
||||
private BuildData write(int i) {
|
||||
myData[myDataPointer++] = i;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.emojipicker;
|
||||
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
public enum EmojiSkinTone {
|
||||
NO_TONE(""),
|
||||
LIGHT("🏻"),
|
||||
@@ -9,12 +11,12 @@ public enum EmojiSkinTone {
|
||||
MEDIUM_DARK("🏾"),
|
||||
DARK("🏿");
|
||||
|
||||
private final String myValue;
|
||||
@NonNls private final String myValue;
|
||||
|
||||
EmojiSkinTone(String value) {this.myValue = value;}
|
||||
EmojiSkinTone(@NonNls String value) {this.myValue = value;}
|
||||
|
||||
@NonNls
|
||||
public String getStringValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-18
@@ -27,12 +27,16 @@ public class OpenEmojiPickerAction extends DumbAwareAction {
|
||||
|
||||
private static Context getContext(AnActionEvent e, boolean findOnly) {
|
||||
Editor editor = e.getData(CommonDataKeys.EDITOR);
|
||||
if(editor != null) {
|
||||
if(editor.isViewer()) return null;
|
||||
if(findOnly) return Context.FOUND;
|
||||
if (editor != null) {
|
||||
if (editor.isViewer()) return null;
|
||||
if (findOnly) return Context.FOUND;
|
||||
Consumer<String> input;
|
||||
if(editor instanceof EditorImpl) input = ((EditorImpl) editor)::type;
|
||||
else if(editor.getContentComponent() instanceof TypingTarget) input = ((TypingTarget) editor.getContentComponent())::type;
|
||||
if (editor instanceof EditorImpl) {
|
||||
input = ((EditorImpl)editor)::type;
|
||||
}
|
||||
else if (editor.getContentComponent() instanceof TypingTarget) {
|
||||
input = ((TypingTarget)editor.getContentComponent())::type;
|
||||
}
|
||||
else {
|
||||
input = s -> WriteCommandAction.writeCommandAction(editor.getProject()).run(() -> {
|
||||
com.intellij.openapi.editor.Document doc = editor.getDocument();
|
||||
@@ -46,28 +50,29 @@ public class OpenEmojiPickerAction extends DumbAwareAction {
|
||||
}
|
||||
|
||||
Component component = e.getData(PlatformDataKeys.CONTEXT_COMPONENT);
|
||||
if(component instanceof EmojiSearchField) {
|
||||
if (component instanceof EmojiSearchField) {
|
||||
// Easy way to block recursive pickers
|
||||
return null;
|
||||
}
|
||||
|
||||
if(component instanceof TypingTarget) {
|
||||
if(findOnly) return Context.FOUND;
|
||||
if (component instanceof TypingTarget) {
|
||||
if (findOnly) return Context.FOUND;
|
||||
return new Context(
|
||||
((TypingTarget) component)::type,
|
||||
((TypingTarget)component)::type,
|
||||
p -> p.showUnderneathOf(component)
|
||||
);
|
||||
}
|
||||
|
||||
if(component instanceof JTextComponent) {
|
||||
if(findOnly) return Context.FOUND;
|
||||
JTextComponent field = (JTextComponent) component;
|
||||
if (component instanceof JTextComponent) {
|
||||
if (findOnly) return Context.FOUND;
|
||||
JTextComponent field = (JTextComponent)component;
|
||||
Document doc = field.getDocument();
|
||||
return new Context(
|
||||
s -> {
|
||||
try {
|
||||
doc.insertString(field.getCaretPosition(), s, null);
|
||||
} catch (BadLocationException exception) {
|
||||
}
|
||||
catch (BadLocationException exception) {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
},
|
||||
@@ -86,24 +91,21 @@ public class OpenEmojiPickerAction extends DumbAwareAction {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
Context context = getContext(e, false);
|
||||
if(context != null) {
|
||||
if (context != null) {
|
||||
JBPopup popup = EmojiPicker.createPopup(e.getProject(), context.myInputCallback);
|
||||
context.myPopupShowCallback.accept(popup);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static class Context {
|
||||
private static final Context FOUND = new Context(null, null);
|
||||
private final Consumer<String> myInputCallback;
|
||||
private final Consumer<JBPopup> myPopupShowCallback;
|
||||
|
||||
private Context(Consumer<String> inputCallback, Consumer<JBPopup> popupShowCallback) {
|
||||
myInputCallback = inputCallback;
|
||||
myPopupShowCallback = popupShowCallback;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package org.jetbrains.plugins.emojipicker.messages;
|
||||
|
||||
import com.intellij.DynamicBundle;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.PropertyKey;
|
||||
import org.jetbrains.plugins.emojipicker.EmojiCategory;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class EmojiCategoriesBundle extends DynamicBundle {
|
||||
@NonNls private static final String BUNDLE = "messages.EmojiCategoriesBundle";
|
||||
private static final EmojiCategoriesBundle INSTANCE = new EmojiCategoriesBundle();
|
||||
|
||||
private EmojiCategoriesBundle() {
|
||||
super(BUNDLE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static @Nls String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) {
|
||||
return INSTANCE.getMessage(key, params);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key,
|
||||
Object @NotNull ... params) {
|
||||
return INSTANCE.getLazyMessage(key, params);
|
||||
}
|
||||
|
||||
public static @Nls String findNameForCategory(EmojiCategory category) {
|
||||
if (category == null) return null;
|
||||
return message("category.EmojiPicker." + category.getId());
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package org.jetbrains.plugins.emojipicker.messages;
|
||||
|
||||
import com.intellij.DynamicBundle;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.PropertyKey;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class EmojipickerBundle extends DynamicBundle {
|
||||
@NonNls private static final String BUNDLE = "messages.EmojipickerBundle";
|
||||
private static final EmojipickerBundle INSTANCE = new EmojipickerBundle();
|
||||
|
||||
private EmojipickerBundle() {
|
||||
super(BUNDLE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static @Nls String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) {
|
||||
return INSTANCE.getMessage(key, params);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key,
|
||||
Object @NotNull ... params) {
|
||||
return INSTANCE.getLazyMessage(key, params);
|
||||
}
|
||||
}
|
||||
+70
-88
@@ -7,8 +7,9 @@ import com.intellij.openapi.progress.PerformInBackgroundOption;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.emojipicker.Emoji;
|
||||
@@ -32,18 +33,18 @@ import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.jetbrains.plugins.emojipicker.messages.EmojipickerBundle.message;
|
||||
|
||||
@Service
|
||||
@State(name = "EmojiPickerState", storages = @Storage("emoji.picker.xml"))
|
||||
public final class EmojiService implements PersistentStateComponent<EmojiService.State> {
|
||||
|
||||
|
||||
private final List<Emoji> myEmoji;
|
||||
private final List<EmojiCategory> myCategories;
|
||||
private final EmojiCategory myRecentlyUsedCategory;
|
||||
|
||||
private volatile SearchIndex myEmojiSearchIndex;
|
||||
|
||||
private final String[] myEmojiNames;
|
||||
@Nls private final String[] myEmojiNames;
|
||||
private volatile EmojiSkinTone mySkinTone;
|
||||
private volatile boolean dirty;
|
||||
|
||||
@@ -61,62 +62,65 @@ public final class EmojiService implements PersistentStateComponent<EmojiService
|
||||
myCategories = new ArrayList<>();
|
||||
List<Emoji> emoji;
|
||||
SearchIndex searchIndex;
|
||||
String[] emojiNames;
|
||||
@Nls String[] emojiNames;
|
||||
try {
|
||||
try(ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedEmojiPath))) {
|
||||
emoji = (List<Emoji>) in.readObject();
|
||||
try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedEmojiPath))) {
|
||||
emoji = (List<Emoji>)in.readObject();
|
||||
myCategories.add(myRecentlyUsedCategory);
|
||||
myCategories.addAll((List<EmojiCategory>) in.readObject());
|
||||
myCategories.addAll((List<EmojiCategory>)in.readObject());
|
||||
}
|
||||
try(ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedIndexPath))) {
|
||||
searchIndex = new SearchIndex((EmojiSearchIndex) in.readObject());
|
||||
try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedIndexPath))) {
|
||||
searchIndex = new SearchIndex((EmojiSearchIndex)in.readObject());
|
||||
}
|
||||
try(ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedNamesPath))) {
|
||||
emojiNames = (String[]) in.readObject();
|
||||
try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(serializedNamesPath))) {
|
||||
emojiNames = (String[])in.readObject();
|
||||
}
|
||||
} catch (IOException | ClassNotFoundException ignore) {
|
||||
}
|
||||
catch (IOException | ClassNotFoundException ignore) {
|
||||
Files.createDirectories(configDir);
|
||||
EmojiData emojiData = EmojiData.read();
|
||||
emoji = emojiData.myEmoji;
|
||||
myCategories.clear();
|
||||
myCategories.add(myRecentlyUsedCategory);
|
||||
myCategories.addAll(emojiData.myCategories);
|
||||
String[] names = emojiNames = new String[emoji.size()];
|
||||
@Nls String[] names = emojiNames = new String[emoji.size()];
|
||||
CldrData cldr = new CldrData(emojiData);
|
||||
final Locale baseLocale = Locale.ENGLISH;
|
||||
cldr.read(baseLocale, emojiNames);
|
||||
searchIndex = new SearchIndex(cldr.myIndexTree.buildIndex());
|
||||
|
||||
ProgressManager.getInstance().run(
|
||||
new Task.Backgroundable(null, getString("message.EmojiPicker.Initializing"), false, PerformInBackgroundOption.ALWAYS_BACKGROUND) {
|
||||
new Task.Backgroundable(null, message("message.EmojiPicker.Initializing"), false, PerformInBackgroundOption.ALWAYS_BACKGROUND) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
try {
|
||||
try(ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedEmojiPath, StandardOpenOption.CREATE))) {
|
||||
try (ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedEmojiPath, StandardOpenOption.CREATE))) {
|
||||
out.writeObject(emojiData.myEmoji);
|
||||
out.writeObject(emojiData.myCategories);
|
||||
}
|
||||
try(ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedNamesPath, StandardOpenOption.CREATE))) {
|
||||
try (ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedNamesPath, StandardOpenOption.CREATE))) {
|
||||
out.writeObject(names);
|
||||
}
|
||||
indicator.setText(getString("message.EmojiPicker.BuildingIndex"));
|
||||
indicator.setText(message("message.EmojiPicker.BuildingIndex"));
|
||||
indicator.setIndeterminate(false);
|
||||
Locale[] locales = Locale.getAvailableLocales();
|
||||
double multiplier = 1.0 / (double) locales.length;
|
||||
double multiplier = 1.0 / (double)locales.length;
|
||||
for (int i = 0; i < locales.length; i++) {
|
||||
indicator.setFraction((double) i * multiplier);
|
||||
if(!locales[i].equals(baseLocale)) cldr.read(locales[i], null);
|
||||
indicator.setFraction((double)i * multiplier);
|
||||
if (!locales[i].equals(baseLocale)) cldr.read(locales[i], null);
|
||||
}
|
||||
indicator.setIndeterminate(true);
|
||||
SearchIndex searchIndex = new SearchIndex(cldr.myIndexTree.buildIndex());
|
||||
indicator.setText(getString("message.EmojiPicker.SavingIndexData"));
|
||||
try(ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedIndexPath, StandardOpenOption.CREATE))) {
|
||||
indicator.setText(message("message.EmojiPicker.SavingIndexData"));
|
||||
try (ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(serializedIndexPath, StandardOpenOption.CREATE))) {
|
||||
out.writeObject(searchIndex.myIndex);
|
||||
}
|
||||
myEmojiSearchIndex = searchIndex;
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
} catch (SAXException e) {
|
||||
}
|
||||
catch (SAXException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@@ -132,30 +136,18 @@ public final class EmojiService implements PersistentStateComponent<EmojiService
|
||||
return myCategories;
|
||||
}
|
||||
|
||||
public @NlsSafe String getString(String key) throws MissingResourceException {
|
||||
return ResourceBundle.getBundle("/messages/EmojipickerBundle").getString(key);
|
||||
}
|
||||
|
||||
public @NlsSafe String findNameForCategory(EmojiCategory category) {
|
||||
if(category == null) return null;
|
||||
try {
|
||||
return getString("category.EmojiPicker." + category.getId());
|
||||
} catch (MissingResourceException ignore) {
|
||||
return category.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@Nls
|
||||
public String findNameForEmoji(Emoji emoji) {
|
||||
return emoji == null ? null : myEmojiNames[emoji.getId()];
|
||||
}
|
||||
|
||||
public List<Emoji> findEmojiByPrefix(String prefix) {
|
||||
public List<Emoji> findEmojiByPrefix(@NonNls String prefix) {
|
||||
return myEmojiSearchIndex.lookupEmoji(prefix);
|
||||
}
|
||||
|
||||
public void saveRecentlyUsedEmoji(Emoji emoji) {
|
||||
myRecentlyUsedCategory.getEmoji().remove(emoji);
|
||||
while(myRecentlyUsedCategory.getEmoji().size() >= 32) {
|
||||
while (myRecentlyUsedCategory.getEmoji().size() >= 32) {
|
||||
myRecentlyUsedCategory.getEmoji().remove(myRecentlyUsedCategory.getEmoji().size() - 1);
|
||||
}
|
||||
myRecentlyUsedCategory.getEmoji().add(0, emoji);
|
||||
@@ -173,15 +165,15 @@ public final class EmojiService implements PersistentStateComponent<EmojiService
|
||||
|
||||
@Override
|
||||
public @Nullable State getState() {
|
||||
if(!dirty) return null;
|
||||
if (!dirty) return null;
|
||||
dirty = false;
|
||||
return new State(mySkinTone, ContainerUtil.map(myRecentlyUsedCategory.getEmoji(), Emoji::getId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(@NotNull State state) {
|
||||
if(state.mySkinTone != null) mySkinTone = state.mySkinTone;
|
||||
if(state.myRecentlyUsedEmoji != null && !state.myRecentlyUsedEmoji.isEmpty()) {
|
||||
if (state.mySkinTone != null) mySkinTone = state.mySkinTone;
|
||||
if (state.myRecentlyUsedEmoji != null && !state.myRecentlyUsedEmoji.isEmpty()) {
|
||||
myRecentlyUsedCategory.getEmoji().clear();
|
||||
myRecentlyUsedCategory.getEmoji().addAll(ContainerUtil.map(state.myRecentlyUsedEmoji, myEmoji::get));
|
||||
}
|
||||
@@ -192,9 +184,6 @@ public final class EmojiService implements PersistentStateComponent<EmojiService
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static class State {
|
||||
|
||||
public EmojiSkinTone mySkinTone;
|
||||
@@ -202,6 +191,7 @@ public final class EmojiService implements PersistentStateComponent<EmojiService
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private State() { this(EmojiSkinTone.NO_TONE, List.of()); }
|
||||
|
||||
private State(EmojiSkinTone tone, List<Integer> emoji) {
|
||||
mySkinTone = tone;
|
||||
myRecentlyUsedEmoji = emoji;
|
||||
@@ -219,13 +209,9 @@ public final class EmojiService implements PersistentStateComponent<EmojiService
|
||||
public int hashCode() {
|
||||
return Objects.hash(mySkinTone, myRecentlyUsedEmoji);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private class SearchIndex {
|
||||
|
||||
private final EmojiSearchIndex myIndex;
|
||||
@@ -236,40 +222,40 @@ public final class EmojiService implements PersistentStateComponent<EmojiService
|
||||
myIdMap = new boolean[index.getTotalEmojiIndices()];
|
||||
}
|
||||
|
||||
synchronized List<Emoji> lookupEmoji(String prefix) {
|
||||
if(myIndex.lookupIds(myIdMap, prefix)) {
|
||||
synchronized List<Emoji> lookupEmoji(@NonNls String prefix) {
|
||||
if (myIndex.lookupIds(myIdMap, prefix)) {
|
||||
List<Emoji> result = new ArrayList<>(100);
|
||||
for (int i = 0; i < myIdMap.length; i++) {
|
||||
if(myIdMap[i]) result.add(myEmoji.get(i));
|
||||
if (myIdMap[i]) result.add(myEmoji.get(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else return List.of();
|
||||
else {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static class EmojiData {
|
||||
|
||||
private final List<Emoji> myEmoji = new ArrayList<>();
|
||||
private final List<EmojiCategory> myCategories = new ArrayList<>();
|
||||
private final Map<String, Integer> myIndicesMap = new HashMap<>();
|
||||
private final Map<@NonNls String, Integer> myIndicesMap = new HashMap<>();
|
||||
|
||||
private static EmojiData read() throws IOException {
|
||||
Set<String> tonedEmojiSet = readToned();
|
||||
Set<@NonNls String> tonedEmojiSet = readToned();
|
||||
EmojiData emojiData = new EmojiData();
|
||||
try(BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
EmojiService.class.getResourceAsStream("/data/emoji.txt"), StandardCharsets.UTF_8))) {
|
||||
EmojiCategory category = null;
|
||||
String s;
|
||||
while((s = reader.readLine()) != null) {
|
||||
if(s.isBlank()) category = null;
|
||||
@NonNls String s;
|
||||
while ((s = reader.readLine()) != null) {
|
||||
if (s.isBlank()) {
|
||||
category = null;
|
||||
}
|
||||
else {
|
||||
if(category == null) {
|
||||
if (category == null) {
|
||||
emojiData.myCategories.add(category = new EmojiCategory(s, new ArrayList<>()));
|
||||
}
|
||||
else {
|
||||
@@ -285,19 +271,15 @@ public final class EmojiService implements PersistentStateComponent<EmojiService
|
||||
return emojiData;
|
||||
}
|
||||
|
||||
private static Set<String> readToned() throws IOException {
|
||||
try(BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
private static Set<@NonNls String> readToned() throws IOException {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
EmojiService.class.getResourceAsStream("/data/toned.txt"), StandardCharsets.UTF_8))) {
|
||||
return reader.lines().collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static class CldrData {
|
||||
|
||||
private final EmojiData myEmojiData;
|
||||
@@ -316,38 +298,38 @@ public final class EmojiService implements PersistentStateComponent<EmojiService
|
||||
myDocumentBuilder = factory.newDocumentBuilder();
|
||||
}
|
||||
|
||||
private void read(Locale locale, String[] names) throws IOException, SAXException {
|
||||
String l = locale.getLanguage();
|
||||
if(!locale.getScript().isEmpty()) l += "_" + locale.getScript();
|
||||
if(!locale.getCountry().isEmpty()) l += "_" + locale.getCountry();
|
||||
private void read(Locale locale, @Nls String[] names) throws IOException, SAXException {
|
||||
@NonNls String l = locale.getLanguage();
|
||||
if (!locale.getScript().isEmpty()) l += "_" + locale.getScript();
|
||||
if (!locale.getCountry().isEmpty()) l += "_" + locale.getCountry();
|
||||
InputStream annotations = EmojiService.class.getResourceAsStream("/data/cldr/annotations/" + l + ".xml");
|
||||
if(annotations != null) read(annotations, locale, names);
|
||||
if (annotations != null) read(annotations, locale, names);
|
||||
InputStream derived = EmojiService.class.getResourceAsStream("/data/cldr/annotationsDerived/" + l + ".xml");
|
||||
if(derived != null) read(derived, locale, names);
|
||||
if (derived != null) read(derived, locale, names);
|
||||
}
|
||||
|
||||
private void read(InputStream in, Locale locale, String[] names) throws IOException, SAXException {
|
||||
try(in) {
|
||||
private void read(InputStream in, Locale locale, @Nls String[] names) throws IOException, SAXException {
|
||||
try (in) {
|
||||
Document document = myDocumentBuilder.parse(in);
|
||||
NodeList annotations = document.getElementsByTagName("annotation");
|
||||
for (int i = 0; i < annotations.getLength(); i++) {
|
||||
Node node = annotations.item(i);
|
||||
String emoji = node.getAttributes().getNamedItem("cp").getTextContent();
|
||||
@NonNls String emoji = node.getAttributes().getNamedItem("cp").getTextContent();
|
||||
Integer index = myEmojiData.myIndicesMap.get(emoji);
|
||||
if(index != null) {
|
||||
String value = node.getTextContent();
|
||||
if(node.getAttributes().getNamedItem("type") == null) {
|
||||
for(String keyword : value.split("\\|")) {
|
||||
if (index != null) {
|
||||
@NonNls String value = node.getTextContent();
|
||||
if (node.getAttributes().getNamedItem("type") == null) {
|
||||
for (String keyword : value.split("\\|")) {
|
||||
myIndexTree.add(keyword.strip(), index);
|
||||
}
|
||||
}
|
||||
else if(names != null) names[index] = value.substring(0, 1).toUpperCase(locale) + value.substring(1);
|
||||
else if (names != null) {
|
||||
@Nls String name = value.substring(0, 1).toUpperCase(locale) + value.substring(1);
|
||||
names[index] = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+6
-7
@@ -4,15 +4,15 @@ package org.jetbrains.plugins.emojipicker.ui;
|
||||
import com.intellij.ui.InplaceButton;
|
||||
import com.intellij.ui.scale.JBUIScale;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.plugins.emojipicker.EmojiCategory;
|
||||
import org.jetbrains.plugins.emojipicker.service.EmojiService;
|
||||
import org.jetbrains.plugins.emojipicker.messages.EmojiCategoriesBundle;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
class EmojiCategoryPanel extends JPanel {
|
||||
|
||||
private final EmojiPickerStyle myStyle;
|
||||
private EmojiCategory myActiveCategory;
|
||||
|
||||
@@ -27,18 +27,18 @@ class EmojiCategoryPanel extends JPanel {
|
||||
gbc.gridy = 0;
|
||||
gbc.insets = JBUI.insets(0, 4);
|
||||
setLayout(new GridBagLayout());
|
||||
for(EmojiCategory category : categories) {
|
||||
String name = EmojiService.getInstance().findNameForCategory(category);
|
||||
for (EmojiCategory category : categories) {
|
||||
@Nls String name = EmojiCategoriesBundle.findNameForCategory(category);
|
||||
InplaceButton button = new InplaceButton(name, category.getIcon(), e -> emojiPicker.selectCategory(category, true)) {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
if(emojiPicker.getCurrentFocusTarget() == category) {
|
||||
if (emojiPicker.getCurrentFocusTarget() == category) {
|
||||
int x = getWidth() / 2, y = getHeight() / 2;
|
||||
g.setColor(myStyle.myFocusBorderColor);
|
||||
g.drawRoundRect(x - 15, y - 15, 30, 30, 4, 4);
|
||||
}
|
||||
if(myActiveCategory == category) {
|
||||
if (myActiveCategory == category) {
|
||||
g.setColor(myStyle.mySelectedCategoryColor);
|
||||
g.fillRect(0, getHeight() - 2, getWidth(), 2);
|
||||
}
|
||||
@@ -62,5 +62,4 @@ class EmojiCategoryPanel extends JPanel {
|
||||
myActiveCategory = category;
|
||||
repaint();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
package org.jetbrains.plugins.emojipicker.ui;
|
||||
|
||||
import com.intellij.ide.ui.AntialiasingType;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.ui.scale.JBUIScale;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.plugins.emojipicker.Emoji;
|
||||
import org.jetbrains.plugins.emojipicker.EmojiSkinTone;
|
||||
import org.jetbrains.plugins.emojipicker.service.EmojiService;
|
||||
@@ -12,10 +14,9 @@ import java.awt.*;
|
||||
import java.awt.font.TextLayout;
|
||||
|
||||
public class EmojiInfoPanel extends JPanel {
|
||||
|
||||
private final EmojiPickerStyle myStyle;
|
||||
private String myCurrentEmoji;
|
||||
private String myCurrentEmojiName;
|
||||
@NlsSafe private String myCurrentEmoji;
|
||||
@Nls private String myCurrentEmojiName;
|
||||
|
||||
EmojiInfoPanel(EmojiPickerStyle style) {
|
||||
myStyle = style;
|
||||
@@ -26,16 +27,16 @@ public class EmojiInfoPanel extends JPanel {
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false));
|
||||
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false));
|
||||
g.setColor(myCurrentEmoji != null ? myStyle.myToolbarColor : myStyle.myBackgroundColor);
|
||||
g.fillRoundRect(0, 0, getWidth(), getHeight(), 6, 6);
|
||||
g.fillRect(0, 0, getWidth(), getHeight() - 6);
|
||||
if(myCurrentEmoji != null) {
|
||||
if (myCurrentEmoji != null) {
|
||||
g.setColor(myStyle.myBorderColor);
|
||||
g.drawLine(0, 0, getWidth(), 0);
|
||||
new TextLayout(myCurrentEmoji, myStyle.myEmojiFont, ((Graphics2D) g).getFontRenderContext())
|
||||
.draw((Graphics2D) g, 16, getHeight() - 17);
|
||||
if(myCurrentEmojiName != null) {
|
||||
new TextLayout(myCurrentEmoji, myStyle.myEmojiFont, ((Graphics2D)g).getFontRenderContext())
|
||||
.draw((Graphics2D)g, 16, getHeight() - 17);
|
||||
if (myCurrentEmojiName != null) {
|
||||
g.setFont(myStyle.myFont);
|
||||
g.setColor(myStyle.myTextColor);
|
||||
g.drawString(myCurrentEmojiName, 49, getHeight() - 20);
|
||||
@@ -44,7 +45,7 @@ public class EmojiInfoPanel extends JPanel {
|
||||
}
|
||||
|
||||
void showEmojiInfo(Emoji emoji, EmojiSkinTone skinTone) {
|
||||
if(emoji == null) {
|
||||
if (emoji == null) {
|
||||
myCurrentEmoji = myCurrentEmojiName = null;
|
||||
}
|
||||
else {
|
||||
@@ -53,5 +54,4 @@ public class EmojiInfoPanel extends JPanel {
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,9 +8,13 @@ import com.intellij.util.ImageLoader;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.StartupUiUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.plugins.emojipicker.Emoji;
|
||||
import org.jetbrains.plugins.emojipicker.EmojiCategory;
|
||||
import org.jetbrains.plugins.emojipicker.EmojiSkinTone;
|
||||
import org.jetbrains.plugins.emojipicker.messages.EmojiCategoriesBundle;
|
||||
import org.jetbrains.plugins.emojipicker.messages.EmojipickerBundle;
|
||||
import org.jetbrains.plugins.emojipicker.service.EmojiService;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -24,8 +28,6 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
class EmojiListPanel extends JBScrollPane {
|
||||
|
||||
|
||||
private static final Image NO_EMOJI_FOUND_IMAGE = ImageLoader.scaleImage(Objects.requireNonNull(
|
||||
ImageLoader.loadFromStream(EmojiListPanel.class.getResourceAsStream("/icons/NoEmojiFound.png"))), 40);
|
||||
private final Dimension myCellSize = new Dimension(JBUIScale.scale(40), JBUIScale.scale(40));
|
||||
@@ -58,30 +60,34 @@ class EmojiListPanel extends JBScrollPane {
|
||||
}
|
||||
});
|
||||
getViewport().addChangeListener(e -> {
|
||||
if(myCurrentPanel == myCategoriesPanel) {
|
||||
if (myCurrentPanel == myCategoriesPanel) {
|
||||
Component topComponent = myCategoriesPanel.getComponentAt(getViewport().getViewPosition());
|
||||
if(topComponent instanceof Category) emojiPicker.selectCategory(((Category) topComponent).myCategory, false);
|
||||
else emojiPicker.selectCategory(myCategoriesPanel.myCategories.get(0).myCategory, false);
|
||||
if (topComponent instanceof Category) {
|
||||
emojiPicker.selectCategory(((Category)topComponent).myCategory, false);
|
||||
}
|
||||
else {
|
||||
emojiPicker.selectCategory(myCategoriesPanel.myCategories.get(0).myCategory, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
setBorder(JBUI.Borders.customLine(myStyle.myBorderColor, 1, 0, 0, 0));
|
||||
}
|
||||
|
||||
void selectCategory(EmojiCategory category) {
|
||||
if(myCurrentPanel != myCategoriesPanel) {
|
||||
if (myCurrentPanel != myCategoriesPanel) {
|
||||
setViewportView(myCurrentPanel = myCategoriesPanel);
|
||||
}
|
||||
if(category == null || category == myCategoriesPanel.myCategories.get(0).myCategory) {
|
||||
if (category == null || category == myCategoriesPanel.myCategories.get(0).myCategory) {
|
||||
setCurrentItem(myCategoriesPanel.myCategories.get(0).myCategory.getEmoji().isEmpty() ?
|
||||
myCategoriesPanel.myCategories.get(1) : myCategoriesPanel.myCategories.get(0), 0);
|
||||
myCategoriesPanel.scrollRectToVisible(new Rectangle(0, 0, 1, getHeight()));
|
||||
}
|
||||
else {
|
||||
Category cat = null;
|
||||
for(Category c : myCategoriesPanel.myCategories) {
|
||||
if(c.myCategory == category) cat = c;
|
||||
for (Category c : myCategoriesPanel.myCategories) {
|
||||
if (c.myCategory == category) cat = c;
|
||||
}
|
||||
if(cat == null) return;
|
||||
if (cat == null) return;
|
||||
setCurrentItem(cat, 0);
|
||||
cat.scrollRectToVisible(new Rectangle(0, 0, 1, getHeight()));
|
||||
}
|
||||
@@ -90,52 +96,56 @@ class EmojiListPanel extends JBScrollPane {
|
||||
void updateSkinTone(EmojiSkinTone skinTone) {
|
||||
myCurrentSkinTone = skinTone;
|
||||
myCurrentPanel.repaint();
|
||||
if(myCurrentItemCategory != null && myCurrentItemIndex >= 0) {
|
||||
if (myCurrentItemCategory != null && myCurrentItemIndex >= 0) {
|
||||
myEmojiPicker.updateEmojiInfo(myCurrentItemCategory.myCategory.getEmoji().get(myCurrentItemIndex), myCurrentSkinTone);
|
||||
}
|
||||
}
|
||||
|
||||
void updateSearchFilter(String text) {
|
||||
if(text.isEmpty()) {
|
||||
void updateSearchFilter(@NonNls String text) {
|
||||
if (text.isEmpty()) {
|
||||
myEmojiPicker.selectCategory(myCategoriesPanel.myCategories.get(0).myCategory, true);
|
||||
}
|
||||
else {
|
||||
myEmojiPicker.selectCategory(null, false);
|
||||
mySearchCategoryPanel.myCategory = new EmojiCategory(null, EmojiService.getInstance().findEmojiByPrefix(text.strip()));
|
||||
mySearchCategoryPanel.updateLayout(getWidth());
|
||||
if(mySearchCategoryPanel.myCategory.getEmoji().isEmpty()) setCurrentItem(null, -1);
|
||||
else setCurrentItem(mySearchCategoryPanel, 0);
|
||||
if (mySearchCategoryPanel.myCategory.getEmoji().isEmpty()) {
|
||||
setCurrentItem(null, -1);
|
||||
}
|
||||
else {
|
||||
setCurrentItem(mySearchCategoryPanel, 0);
|
||||
}
|
||||
setViewportView(myCurrentPanel = mySearchCategoryPanel);
|
||||
}
|
||||
}
|
||||
|
||||
void selectCurrentEmoji() {
|
||||
if(!hasCurrentItem()) return;
|
||||
if (!hasCurrentItem()) return;
|
||||
Emoji emoji = myCurrentItemCategory.myCategory.getEmoji().get(myCurrentItemIndex);
|
||||
EmojiService.getInstance().saveRecentlyUsedEmoji(emoji);
|
||||
myEmojiPicker.selectEmoji(emoji.getTonedValue(myCurrentSkinTone));
|
||||
}
|
||||
|
||||
void navigate(int dx, int dy) {
|
||||
if(myCurrentItemIndex < 0) return;
|
||||
if (myCurrentItemIndex < 0) return;
|
||||
int x = (myCurrentItemIndex % myItemsPerRow + dx + myItemsPerRow) % myItemsPerRow;
|
||||
int y = myCurrentItemIndex / myItemsPerRow + dy;
|
||||
int newIndex = myItemsPerRow * y + x;
|
||||
if(newIndex >= 0 && newIndex < myCurrentItemCategory.myCategory.getEmoji().size()) {
|
||||
if (newIndex >= 0 && newIndex < myCurrentItemCategory.myCategory.getEmoji().size()) {
|
||||
setCurrentItem(myCurrentItemCategory, newIndex);
|
||||
}
|
||||
else {
|
||||
int cat = myCategoriesPanel.findCategoryIndex(myCurrentItemCategory);
|
||||
if(cat == -1) return;
|
||||
if (cat == -1) return;
|
||||
boolean up = newIndex < 0;
|
||||
cat += up ? -1 : 1;
|
||||
if(cat < 0 || cat >= myCategoriesPanel.myCategories.size()) return;
|
||||
if (cat < 0 || cat >= myCategoriesPanel.myCategories.size()) return;
|
||||
Category c = myCategoriesPanel.myCategories.get(cat);
|
||||
int rows = (c.myCategory.getEmoji().size() + myItemsPerRow - 1) / myItemsPerRow;
|
||||
y = up ? rows - 1 : 0;
|
||||
if(y < 0 || myItemsPerRow * y + x >= c.myCategory.getEmoji().size()) {
|
||||
if (y < 0 || myItemsPerRow * y + x >= c.myCategory.getEmoji().size()) {
|
||||
y--;
|
||||
if(y < 0) return;
|
||||
if (y < 0) return;
|
||||
}
|
||||
setCurrentItem(c, myItemsPerRow * y + x);
|
||||
}
|
||||
@@ -162,9 +172,6 @@ class EmojiListPanel extends JBScrollPane {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private abstract class UpdatableLayoutPanel extends JPanel {
|
||||
|
||||
private UpdatableLayoutPanel() {
|
||||
@@ -172,7 +179,6 @@ class EmojiListPanel extends JBScrollPane {
|
||||
}
|
||||
|
||||
abstract void updateLayout(int width);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -184,21 +190,20 @@ class EmojiListPanel extends JBScrollPane {
|
||||
myCategories = categories;
|
||||
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
add(Box.createRigidArea(new Dimension(0, 15)));
|
||||
for(Category c : categories) add(c);
|
||||
for (Category c : categories) add(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateLayout(int width) {
|
||||
for(Category c : myCategories) c.updateLayout(width);
|
||||
for (Category c : myCategories) c.updateLayout(width);
|
||||
}
|
||||
|
||||
private int findCategoryIndex(Category c) {
|
||||
for (int i = 0; i < myCategories.size(); i++) {
|
||||
if(myCategories.get(i) == c) return i;
|
||||
if (myCategories.get(i) == c) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -207,37 +212,42 @@ class EmojiListPanel extends JBScrollPane {
|
||||
private static final int NO_LABEL_PADDING = 12;
|
||||
private static final int LABEL_HEIGHT = 32;
|
||||
private EmojiCategory myCategory;
|
||||
private final String myName;
|
||||
@Nls private final String myName;
|
||||
private final Insets myPadding;
|
||||
|
||||
private Category(EmojiCategory category) {
|
||||
myCategory = category;
|
||||
myName = EmojiService.getInstance().findNameForCategory(category);
|
||||
myName = EmojiCategoriesBundle.findNameForCategory(category);
|
||||
myPadding = JBUI.insets(myName == null ? NO_LABEL_PADDING : LABEL_HEIGHT, myHorizontalPadding, 8, myHorizontalPadding);
|
||||
MouseAdapter mouseAdapter = new MouseAdapter() {
|
||||
private int getItemIndexUnderCursor(Point point) {
|
||||
if(point.x < myPadding.left || point.y < myPadding.top) return -1;
|
||||
if (point.x < myPadding.left || point.y < myPadding.top) return -1;
|
||||
int x = xVisibleToGrid(point.x), y = yVisibleToGrid(point.y);
|
||||
if(x >= myItemsPerRow || point.x > xGridToVisible(x) + myCellSize.width || point.y > yGridToVisible(y) + myCellSize.height) {
|
||||
if (x >= myItemsPerRow || point.x > xGridToVisible(x) + myCellSize.width || point.y > yGridToVisible(y) + myCellSize.height) {
|
||||
return -1;
|
||||
}
|
||||
int index = myItemsPerRow * y + x;
|
||||
return index >= 0 && index < myCategory.getEmoji().size() ? index : -1;
|
||||
}
|
||||
|
||||
private boolean setCurrentItemUnderCursor(Point point) {
|
||||
int item = getItemIndexUnderCursor(point);
|
||||
if(item != -1) {
|
||||
if (item != -1) {
|
||||
setCurrentItem(Category.this, item);
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if(setCurrentItemUnderCursor(e.getPoint())) {
|
||||
if (setCurrentItemUnderCursor(e.getPoint())) {
|
||||
selectCurrentEmoji();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
setCurrentItemUnderCursor(e.getPoint());
|
||||
@@ -250,12 +260,15 @@ class EmojiListPanel extends JBScrollPane {
|
||||
private int xVisibleToGrid(int x) {
|
||||
return (x - myPadding.left) / (myCellSize.width + myCellGaps.width);
|
||||
}
|
||||
|
||||
private int yVisibleToGrid(int y) {
|
||||
return (y - myPadding.top) / (myCellSize.height + myCellGaps.height);
|
||||
}
|
||||
|
||||
private int xGridToVisible(int x) {
|
||||
return x * (myCellSize.width + myCellGaps.width) + myPadding.left;
|
||||
}
|
||||
|
||||
private int yGridToVisible(int y) {
|
||||
return y * (myCellSize.height + myCellGaps.height) + myPadding.top;
|
||||
}
|
||||
@@ -277,21 +290,23 @@ class EmojiListPanel extends JBScrollPane {
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
super.paint(g);
|
||||
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false));
|
||||
if(myName == null && myCategory.getEmoji().isEmpty()) paintNoEmojiFound(g);
|
||||
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false));
|
||||
if (myName == null && myCategory.getEmoji().isEmpty()) {
|
||||
paintNoEmojiFound(g);
|
||||
}
|
||||
else {
|
||||
if(myItemsPerRow <= 0) return;
|
||||
if (myItemsPerRow <= 0) return;
|
||||
paintSelection(g);
|
||||
paintItems(g);
|
||||
if(myName != null) paintCategoryLabel(g);
|
||||
if (myName != null) paintCategoryLabel(g);
|
||||
}
|
||||
}
|
||||
|
||||
private void paintNoEmojiFound(Graphics g) {
|
||||
if(g instanceof Graphics2D) {
|
||||
if (g instanceof Graphics2D) {
|
||||
int x = (getWidth() - NO_EMOJI_FOUND_IMAGE.getWidth(this)) / 2;
|
||||
int y = (getHeight() - NO_EMOJI_FOUND_IMAGE.getHeight(this)) / 2;
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
Graphics2D g2 = (Graphics2D)g;
|
||||
final Composite saveComposite = g2.getComposite();
|
||||
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5F));
|
||||
StartupUiUtil.drawImage(g, NO_EMOJI_FOUND_IMAGE, x, y, null);
|
||||
@@ -299,14 +314,14 @@ class EmojiListPanel extends JBScrollPane {
|
||||
}
|
||||
g.setColor(myStyle.myNoEmojiFoundTextColor);
|
||||
g.setFont(myStyle.myLightFont);
|
||||
String message = "No emoji found";
|
||||
@Nls String message = EmojipickerBundle.message("message.EmojiPicker.NoEmojiFound");
|
||||
int x = (getWidth() - g.getFontMetrics().stringWidth(message)) / 2;
|
||||
int y = (getHeight() + NO_EMOJI_FOUND_IMAGE.getHeight(this)) / 2 + 25;
|
||||
g.drawString(message, x, y);
|
||||
}
|
||||
|
||||
private void paintSelection(Graphics g) {
|
||||
if(myCurrentItemCategory == this && myCurrentItemIndex != -1) {
|
||||
if (myCurrentItemCategory == this && myCurrentItemIndex != -1) {
|
||||
int x = xGridToVisible(myCurrentItemIndex % myItemsPerRow);
|
||||
int y = yGridToVisible(myCurrentItemIndex / myItemsPerRow);
|
||||
g.setColor(myStyle.myHoverBackgroundColor);
|
||||
@@ -317,18 +332,18 @@ class EmojiListPanel extends JBScrollPane {
|
||||
private void paintItems(Graphics g) {
|
||||
Rectangle bounds = g.getClipBounds();
|
||||
int from = yVisibleToGrid(bounds.y) * myItemsPerRow, to = yVisibleToGrid(bounds.y + bounds.height) * myItemsPerRow + myItemsPerRow;
|
||||
if(from < 0) from = 0;
|
||||
if (from < 0) from = 0;
|
||||
int itemCount = myCategory.getEmoji().size();
|
||||
if(to > itemCount) to = itemCount;
|
||||
if(from > to) from = to;
|
||||
if (to > itemCount) to = itemCount;
|
||||
if (from > to) from = to;
|
||||
FontMetrics metrics = g.getFontMetrics(myStyle.myEmojiFont);
|
||||
int verticalOffset = metrics.getHeight() / 2 - metrics.getDescent();
|
||||
for (int i = from; i < to; i++) {
|
||||
int x = xGridToVisible(i % myItemsPerRow), y = yGridToVisible(i / myItemsPerRow);
|
||||
String item = myCategory.getEmoji().get(i).getTonedValue(myCurrentSkinTone);
|
||||
@Nls String item = myCategory.getEmoji().get(i).getTonedValue(myCurrentSkinTone);
|
||||
int width = metrics.stringWidth(item);
|
||||
new TextLayout(item, myStyle.myEmojiFont, ((Graphics2D) g).getFontRenderContext())
|
||||
.draw((Graphics2D) g,x + (myCellSize.width - width) / 2F, y + myCellSize.height / 2F + verticalOffset);
|
||||
new TextLayout(item, myStyle.myEmojiFont, ((Graphics2D)g).getFontRenderContext())
|
||||
.draw((Graphics2D)g, x + (myCellSize.width - width) / 2F, y + myCellSize.height / 2F + verticalOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,8 +355,5 @@ class EmojiListPanel extends JBScrollPane {
|
||||
g.setColor(myStyle.myTextColor);
|
||||
g.drawString(myName, 16, offset + 20);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.ui.WindowMoveListener;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.plugins.emojipicker.Emoji;
|
||||
import org.jetbrains.plugins.emojipicker.EmojiCategory;
|
||||
import org.jetbrains.plugins.emojipicker.EmojiSkinTone;
|
||||
@@ -22,8 +23,6 @@ import java.util.function.Consumer;
|
||||
|
||||
|
||||
public class EmojiPicker extends JLayeredPane {
|
||||
|
||||
|
||||
private final List<EmojiCategory> myCategories;
|
||||
private final EmojiSearchField mySearchField;
|
||||
private final EmojiCategoryPanel myCategoryPanel;
|
||||
@@ -32,7 +31,8 @@ public class EmojiPicker extends JLayeredPane {
|
||||
private final JPanel myEmojiSkinTonesModal;
|
||||
private final EmojiSkinTonesPanel myEmojiSkinTonesPanel;
|
||||
private final KeyboardManager myKeyboardManager;
|
||||
private Consumer<String> myInputCallback = emoji -> {};
|
||||
private Consumer<String> myInputCallback = emoji -> {
|
||||
};
|
||||
|
||||
|
||||
private EmojiPicker() {
|
||||
@@ -43,7 +43,7 @@ public class EmojiPicker extends JLayeredPane {
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
gbc.weightx = 1;
|
||||
gbc.gridx = 0;
|
||||
GridBagConstraints fillerGbc = (GridBagConstraints) gbc.clone();
|
||||
GridBagConstraints fillerGbc = (GridBagConstraints)gbc.clone();
|
||||
fillerGbc.weighty = 1;
|
||||
|
||||
EmojiPickerStyle style = new EmojiPickerStyle();
|
||||
@@ -78,6 +78,7 @@ public class EmojiPicker extends JLayeredPane {
|
||||
selectCategory(myCategories.get(0), true);
|
||||
selectSkinToneFromPanel();
|
||||
}
|
||||
|
||||
private static void applyWindowMoveListener(Component c) {
|
||||
WindowMoveListener listener = new WindowMoveListener(c);
|
||||
c.addMouseListener(listener);
|
||||
@@ -86,14 +87,14 @@ public class EmojiPicker extends JLayeredPane {
|
||||
|
||||
void selectCategory(EmojiCategory category, boolean scrollToCategory) {
|
||||
myCategoryPanel.selectCategory(category);
|
||||
if(scrollToCategory) {
|
||||
if(!mySearchField.getText().isEmpty()) mySearchField.setText("");
|
||||
if (scrollToCategory) {
|
||||
if (!mySearchField.getText().isEmpty()) mySearchField.setText("");
|
||||
myEmojiListPanel.selectCategory(category);
|
||||
myKeyboardManager.resetFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void search(String text) {
|
||||
void search(@NonNls String text) {
|
||||
myEmojiListPanel.updateSearchFilter(text);
|
||||
myKeyboardManager.resetFocus();
|
||||
myKeyboardManager.emojiNavigationMode = false;
|
||||
@@ -103,7 +104,7 @@ public class EmojiPicker extends JLayeredPane {
|
||||
myEmojiInfoPanel.showEmojiInfo(emoji, skinTone);
|
||||
}
|
||||
|
||||
void selectEmoji(String emoji) {
|
||||
void selectEmoji(@NonNls String emoji) {
|
||||
myInputCallback.accept(emoji);
|
||||
}
|
||||
|
||||
@@ -149,19 +150,18 @@ public class EmojiPicker extends JLayeredPane {
|
||||
.setShowBorder(false)
|
||||
.createPopup();
|
||||
picker.myInputCallback = emoji -> {
|
||||
if(emoji != null) {
|
||||
if (emoji != null) {
|
||||
inputCallback.accept(emoji);
|
||||
popup.closeOk(null);
|
||||
}
|
||||
else popup.cancel();
|
||||
else {
|
||||
popup.cancel();
|
||||
}
|
||||
};
|
||||
return popup;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private class KeyboardManager {
|
||||
|
||||
private final List<Object> focusTargets = new ArrayList<>();
|
||||
@@ -175,7 +175,7 @@ public class EmojiPicker extends JLayeredPane {
|
||||
}
|
||||
|
||||
private void resetFocus() {
|
||||
if(currentFocusTarget != 0) {
|
||||
if (currentFocusTarget != 0) {
|
||||
currentFocusTarget = 0;
|
||||
emojiNavigationMode = false;
|
||||
myCategoryPanel.repaint();
|
||||
@@ -185,8 +185,8 @@ public class EmojiPicker extends JLayeredPane {
|
||||
|
||||
private boolean handleKey(int k, int modifiers) {
|
||||
Object focus = focusTargets.get(currentFocusTarget);
|
||||
if(focus == myEmojiSkinTonesPanel) {
|
||||
if(myEmojiSkinTonesPanel.isVisible()) {
|
||||
if (focus == myEmojiSkinTonesPanel) {
|
||||
if (myEmojiSkinTonesPanel.isVisible()) {
|
||||
switch (k) {
|
||||
case KeyEvent.VK_UP:
|
||||
case KeyEvent.VK_DOWN:
|
||||
@@ -201,7 +201,7 @@ public class EmojiPicker extends JLayeredPane {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(k == KeyEvent.VK_ENTER || k == KeyEvent.VK_SPACE) {
|
||||
else if (k == KeyEvent.VK_ENTER || k == KeyEvent.VK_SPACE) {
|
||||
openSkinToneSelectionPanel();
|
||||
myEmojiSkinTonesPanel.focusItem(1);
|
||||
return true;
|
||||
@@ -222,29 +222,31 @@ public class EmojiPicker extends JLayeredPane {
|
||||
case KeyEvent.VK_LEFT:
|
||||
case KeyEvent.VK_RIGHT:
|
||||
resetFocus();
|
||||
if(!emojiNavigationMode) {
|
||||
if (!emojiNavigationMode) {
|
||||
emojiNavigationMode = k == KeyEvent.VK_UP || k == KeyEvent.VK_DOWN ||
|
||||
(k == KeyEvent.VK_LEFT && mySearchField.getCaretPosition() == 0) ||
|
||||
(k == KeyEvent.VK_RIGHT &&
|
||||
mySearchField.getCaretPosition() == mySearchField.getText().length());
|
||||
}
|
||||
if(!myEmojiListPanel.hasCurrentItem()) emojiNavigationMode = false;
|
||||
if(emojiNavigationMode) {
|
||||
if (!myEmojiListPanel.hasCurrentItem()) emojiNavigationMode = false;
|
||||
if (emojiNavigationMode) {
|
||||
myEmojiListPanel.navigate(
|
||||
keyToOffset(k, KeyEvent.VK_RIGHT, KeyEvent.VK_LEFT),
|
||||
keyToOffset(k, KeyEvent.VK_DOWN, KeyEvent.VK_UP)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(focus instanceof EmojiCategory) {
|
||||
if(k == KeyEvent.VK_ENTER || k == KeyEvent.VK_SPACE) {
|
||||
selectCategory((EmojiCategory) focus, true);
|
||||
if (focus instanceof EmojiCategory) {
|
||||
if (k == KeyEvent.VK_ENTER || k == KeyEvent.VK_SPACE) {
|
||||
selectCategory((EmojiCategory)focus, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(focus == mySearchField && k == KeyEvent.VK_ENTER) {
|
||||
else if (focus == mySearchField && k == KeyEvent.VK_ENTER) {
|
||||
myEmojiListPanel.selectCurrentEmoji();
|
||||
return true;
|
||||
}
|
||||
@@ -252,50 +254,53 @@ public class EmojiPicker extends JLayeredPane {
|
||||
}
|
||||
|
||||
private int keyToOffset(int key, int positive, int negative) {
|
||||
if(key == positive) return 1;
|
||||
if(key == negative) return -1;
|
||||
if (key == positive) return 1;
|
||||
if (key == negative) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static class JPanelFillLayout implements LayoutManager2 {
|
||||
@Override
|
||||
public void addLayoutComponent(Component comp, Object constraints) {}
|
||||
|
||||
@Override
|
||||
public Dimension maximumLayoutSize(Container target) { return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); }
|
||||
|
||||
@Override
|
||||
public float getLayoutAlignmentX(Container target) { return 0.5f; }
|
||||
|
||||
@Override
|
||||
public float getLayoutAlignmentY(Container target) { return 0.5f; }
|
||||
|
||||
@Override
|
||||
public void invalidateLayout(Container target) {}
|
||||
|
||||
@Override
|
||||
public void addLayoutComponent(String name, Component comp) {}
|
||||
|
||||
@Override
|
||||
public void removeLayoutComponent(Component comp) {}
|
||||
|
||||
@Override
|
||||
public Dimension preferredLayoutSize(Container parent) {
|
||||
synchronized (parent.getTreeLock()) {
|
||||
return parent.getSize();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); }
|
||||
|
||||
@Override
|
||||
public void layoutContainer(Container parent) {
|
||||
synchronized (parent.getTreeLock()) {
|
||||
Dimension size = parent.getSize();
|
||||
for (int i = 0; i < parent.getComponentCount(); i++) {
|
||||
if(parent.getComponent(i).getClass() == JPanel.class) parent.getComponent(i).setBounds(0, 0, size.width, size.height);
|
||||
if (parent.getComponent(i).getClass() == JPanel.class) parent.getComponent(i).setBounds(0, 0, size.width, size.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import java.util.stream.Stream;
|
||||
|
||||
|
||||
class EmojiPickerStyle {
|
||||
|
||||
final Font myFont = JBUI.Fonts.label().deriveFont(Font.BOLD, JBUIScale.scale(13F));
|
||||
final Font myLightFont = myFont.deriveFont(Font.PLAIN);
|
||||
final Font myEmojiFont = Stream.of(GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts())
|
||||
@@ -28,5 +27,4 @@ class EmojiPickerStyle {
|
||||
final Color myFocusBorderColor = new JBColor(0x97C3F3, 0x97C3F3);
|
||||
final Color myTextColor = JBUI.CurrentTheme.Label.foreground();
|
||||
final Color myNoEmojiFoundTextColor = new JBColor(0x808080, 0xBBBBBB);
|
||||
|
||||
}
|
||||
|
||||
@@ -23,10 +23,12 @@ public class EmojiSearchField extends ExtendableTextField {
|
||||
public Icon getIcon(boolean hovered) {
|
||||
return AllIcons.Actions.Search;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIconBeforeText() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconGap() {
|
||||
return JBUIScale.scale(6);
|
||||
@@ -45,14 +47,17 @@ public class EmojiSearchField extends ExtendableTextField {
|
||||
public Icon getIcon(boolean hovered) {
|
||||
return emojiPicker.getCurrentSkinToneIcon(hovered);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIconBeforeText() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconGap() {
|
||||
return JBUIScale.scale(6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable getActionOnClick() {
|
||||
return emojiPicker::openSkinToneSelectionPanel;
|
||||
@@ -76,14 +81,16 @@ public class EmojiSearchField extends ExtendableTextField {
|
||||
void handle(KeyEvent e, boolean typed) {
|
||||
int c = typed ? e.getKeyChar() : e.getKeyCode();
|
||||
boolean mayIntercept = c == KeyEvent.VK_SPACE || c == KeyEvent.VK_ENTER;
|
||||
if(mayIntercept == typed && emojiPicker.handleKey(c, e.getModifiersEx())) {
|
||||
if (mayIntercept == typed && emojiPicker.handleKey(c, e.getModifiersEx())) {
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
handle(e, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
handle(e, false);
|
||||
@@ -98,12 +105,11 @@ public class EmojiSearchField extends ExtendableTextField {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
if(myEmojiPicker.getCurrentFocusTarget() instanceof EmojiSkinTonesPanel) {
|
||||
if (myEmojiPicker.getCurrentFocusTarget() instanceof EmojiSkinTonesPanel) {
|
||||
g.setColor(myStyle.myFocusBorderColor);
|
||||
Insets i = getInsets();
|
||||
final int SIZE = 30;
|
||||
g.drawRoundRect(getWidth() - i.right - SIZE - 8, getHeight() / 2 - SIZE / 2, SIZE, SIZE, 6, 6);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
-17
@@ -3,6 +3,7 @@ package org.jetbrains.plugins.emojipicker.ui;
|
||||
|
||||
import com.intellij.ide.ui.AntialiasingType;
|
||||
import com.intellij.openapi.ui.popup.IconButton;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.ui.InplaceButton;
|
||||
import org.jetbrains.plugins.emojipicker.EmojiSkinTone;
|
||||
import org.jetbrains.plugins.emojipicker.service.EmojiService;
|
||||
@@ -14,10 +15,8 @@ import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EmojiSkinTonesPanel extends JPanel {
|
||||
|
||||
|
||||
private static final int ITEM_SIZE = 34;
|
||||
private static final String ITEM_EMOJI = "🖐";
|
||||
@NlsSafe private static final String ITEM_EMOJI = "🖐";
|
||||
|
||||
private final EmojiPickerStyle myStyle;
|
||||
private final Map<EmojiSkinTone, Item> myItemMap = new EnumMap<>(EmojiSkinTone.class);
|
||||
@@ -28,7 +27,7 @@ public class EmojiSkinTonesPanel extends JPanel {
|
||||
myStyle = style;
|
||||
setVisible(false);
|
||||
setLayout(new GridBagLayout());
|
||||
for(EmojiSkinTone tone : EmojiSkinTone.values()) {
|
||||
for (EmojiSkinTone tone : EmojiSkinTone.values()) {
|
||||
Item item = new Item(emojiPicker, tone);
|
||||
myItemMap.put(tone, item);
|
||||
}
|
||||
@@ -45,7 +44,7 @@ public class EmojiSkinTonesPanel extends JPanel {
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
super.paint(g);
|
||||
if(myFocusedItem != -1) {
|
||||
if (myFocusedItem != -1) {
|
||||
g.setColor(myStyle.myFocusBorderColor);
|
||||
g.drawRoundRect(3, myFocusedItem * ITEM_SIZE + 3, ITEM_SIZE - 4, ITEM_SIZE - 4, 6, 6);
|
||||
}
|
||||
@@ -66,8 +65,8 @@ public class EmojiSkinTonesPanel extends JPanel {
|
||||
|
||||
void setCurrentItemFromFocus() {
|
||||
Component c = getComponent(myFocusedItem);
|
||||
for(Item item : myItemMap.values()) {
|
||||
if(item.myButton == c) {
|
||||
for (Item item : myItemMap.values()) {
|
||||
if (item.myButton == c) {
|
||||
myCurrentSkinTone = item.myTone;
|
||||
return;
|
||||
}
|
||||
@@ -84,8 +83,8 @@ public class EmojiSkinTonesPanel extends JPanel {
|
||||
gbc.gridx = 0;
|
||||
removeAll();
|
||||
add(myItemMap.get(myCurrentSkinTone).myButton, gbc);
|
||||
for(Map.Entry<EmojiSkinTone, Item> item : myItemMap.entrySet()) {
|
||||
if(item.getKey() != myCurrentSkinTone) add(item.getValue().myButton, gbc);
|
||||
for (Map.Entry<EmojiSkinTone, Item> item : myItemMap.entrySet()) {
|
||||
if (item.getKey() != myCurrentSkinTone) add(item.getValue().myButton, gbc);
|
||||
}
|
||||
doLayout();
|
||||
setVisible(true);
|
||||
@@ -114,33 +113,34 @@ public class EmojiSkinTonesPanel extends JPanel {
|
||||
|
||||
private class Icon implements javax.swing.Icon {
|
||||
private final boolean myHover;
|
||||
|
||||
private Icon(boolean hover) { myHover = hover; }
|
||||
|
||||
@Override
|
||||
public void paintIcon(Component c, Graphics g, int x, int y) {
|
||||
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false));
|
||||
if(myHover) {
|
||||
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, AntialiasingType.getKeyForCurrentScope(false));
|
||||
if (myHover) {
|
||||
g.setColor(myStyle.myHoverBackgroundColor);
|
||||
g.fillRoundRect(x, y, getIconWidth(), getIconHeight(), 6, 6);
|
||||
}
|
||||
|
||||
String emoji = ITEM_EMOJI + myTone.getStringValue();
|
||||
@NlsSafe String emoji = ITEM_EMOJI + myTone.getStringValue();
|
||||
FontMetrics metrics = g.getFontMetrics(myStyle.myEmojiFont);
|
||||
int verticalOffset = metrics.getHeight() / 2 - metrics.getDescent();
|
||||
int width = metrics.stringWidth(emoji);
|
||||
new TextLayout(emoji, myStyle.myEmojiFont, ((Graphics2D) g).getFontRenderContext())
|
||||
.draw((Graphics2D) g, x + (getIconWidth() - width) / 2F, y + getIconHeight() / 2F + verticalOffset);
|
||||
new TextLayout(emoji, myStyle.myEmojiFont, ((Graphics2D)g).getFontRenderContext())
|
||||
.draw((Graphics2D)g, x + (getIconWidth() - width) / 2F, y + getIconHeight() / 2F + verticalOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
return ITEM_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return ITEM_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user