1
1
package com.github.ilovegamecoding.intellijcodexp.managers
2
2
3
3
import com.github.ilovegamecoding.intellijcodexp.enums.Event
4
+ import com.github.ilovegamecoding.intellijcodexp.listeners.CodeXPEventListener
4
5
import com.github.ilovegamecoding.intellijcodexp.listeners.CodeXPListener
6
+ import com.github.ilovegamecoding.intellijcodexp.models.CodeXPChallenge
7
+ import com.github.ilovegamecoding.intellijcodexp.models.CodeXPConfiguration
8
+ import com.github.ilovegamecoding.intellijcodexp.models.CodeXPDialog
9
+ import com.github.ilovegamecoding.intellijcodexp.models.CodeXPLevel
5
10
import com.github.ilovegamecoding.intellijcodexp.services.CodeXPService
6
11
import com.intellij.openapi.actionSystem.CommonDataKeys
7
12
import com.intellij.openapi.actionSystem.DataContext
8
13
import com.intellij.openapi.application.ApplicationManager
14
+ import com.intellij.openapi.diagnostic.thisLogger
15
+ import com.intellij.openapi.project.ProjectManager
16
+ import com.intellij.openapi.wm.WindowManager
9
17
import com.intellij.ui.JBColor
10
18
import java.awt.Color
19
+ import java.awt.Dimension
11
20
import java.awt.Font
12
- import javax.swing.JComponent
13
- import javax.swing.JLabel
21
+ import java.awt.Point
22
+ import java.awt.event.ActionListener
23
+ import java.awt.event.MouseAdapter
24
+ import java.awt.event.MouseMotionAdapter
25
+ import javax.swing.*
14
26
import kotlin.math.max
15
27
28
+
16
29
/* *
17
30
* CodeXPUIManager class
18
31
*
19
32
* This class manages the UI of the CodeXP plugin.
20
33
*/
21
- object CodeXPUIManager : CodeXPListener {
34
+ object CodeXPUIManager : CodeXPEventListener, CodeXPListener {
22
35
/* *
23
36
* Fading labels in each swing component.
24
37
*/
@@ -39,22 +52,55 @@ object CodeXPUIManager : CodeXPListener {
39
52
*/
40
53
private val connection = messageBus.connect()
41
54
55
+ private lateinit var ide: JLayeredPane
56
+ private lateinit var dialogArea: JPanel
57
+ private val dialogTimers: MutableMap <CodeXPDialog , Timer > = mutableMapOf ()
58
+
42
59
init {
43
- connection.subscribe(CodeXPListener .CODEXP_EVENT , this )
60
+ connection.subscribe(CodeXPEventListener .CODEXP_EVENT , this )
61
+ connection.subscribe(CodeXPListener .CODEXP , this )
44
62
}
45
63
46
64
override fun eventOccurred (event : Event , dataContext : DataContext ? ) {
47
65
displayXPLabel(event, dataContext)
48
66
}
49
67
68
+ override fun xpUpdated (levelInfo : CodeXPLevel ) {
69
+
70
+ }
71
+
72
+ override fun levelUp (levelInfo : CodeXPLevel ) {
73
+ showDialog(
74
+ CodeXPDialog .createDialog(
75
+ " Level Up!" ,
76
+ " Congratulations! You have reached level ${levelInfo.level} !" ,
77
+ " XP to next level: ${levelInfo.totalXPForNextLevel} xp"
78
+ )
79
+ )
80
+ }
81
+
82
+ override fun challengeUpdated (event : Event , challenge : CodeXPChallenge , newChallenge : CodeXPChallenge ? ) {
83
+
84
+ }
85
+
86
+ override fun challengeCompleted (event : Event , challenge : CodeXPChallenge ) {
87
+ showDialog(
88
+ CodeXPDialog .createDialog(
89
+ " Challenge Completed!" ,
90
+ " Congratulations! You have completed '${challenge.name} '!" ,
91
+ " XP gained: ${challenge.rewardXP} xp"
92
+ )
93
+ )
94
+ }
95
+
50
96
/* *
51
97
* Display XP label at the caret position.
52
98
*
53
99
* @param event The event to fire.
54
100
* @param dataContext The data context of the event.
55
101
*/
56
102
private fun displayXPLabel (event : Event , dataContext : DataContext ? ) {
57
- if ( dataContext == null ) return
103
+ dataContext ? : return
58
104
59
105
val codeXPConfiguration =
60
106
ApplicationManager .getApplication().getService(CodeXPService ::class .java).state.codeXPConfiguration
@@ -72,9 +118,11 @@ object CodeXPUIManager : CodeXPListener {
72
118
fadingLabels[component]?.let { fadingLabel ->
73
119
fadingLabel.cancelFadeOut()
74
120
currentXPGainValue = fadingLabel.value
75
- component.remove(fadingLabel)
76
- component.revalidate()
77
- component.repaint()
121
+ with (component) {
122
+ remove(fadingLabel)
123
+ revalidate()
124
+ repaint()
125
+ }
78
126
}
79
127
80
128
currentXPGainValue + = event.xpValue.toInt()
@@ -83,48 +131,69 @@ object CodeXPUIManager : CodeXPListener {
83
131
font = Font (font.fontName, Font .BOLD , editor.colorsScheme.editorFontSize)
84
132
size = preferredSize
85
133
val caretHeight = editor.lineHeight
86
- fadingLabelPosition.let { point ->
87
- val position = codeXPConfiguration.positionToDisplayGainedXP
88
- val xOffset = when {
89
- position.name.contains(" LEFT" ) -> - width
90
- position.name.contains(" RIGHT" ) -> 0
91
- else -> - width / 2
92
- }
93
- point.translate(
94
- (position.x * 4 ) + xOffset,
95
- position.y * (caretHeight / 2 )
96
- )
97
- location = point
98
- }
134
+ location =
135
+ calculateLabelLocation(codeXPConfiguration, fadingLabelPosition, caretHeight, preferredSize.width)
99
136
startFadeOut()
100
137
}
101
138
102
139
fadingLabels[component] = newFadingLabel
103
140
104
- component.add(newFadingLabel)
105
- component.revalidate()
106
- component.repaint()
141
+ with (component) {
142
+ add(newFadingLabel)
143
+ revalidate()
144
+ repaint()
145
+ }
146
+ }
147
+
148
+ private fun calculateLabelLocation (
149
+ config : CodeXPConfiguration ,
150
+ point : Point ,
151
+ caretHeight : Int ,
152
+ labelWidth : Int
153
+ ): Point {
154
+ with (config.positionToDisplayGainedXP) {
155
+ val xOffset = when {
156
+ name.contains(" LEFT" ) -> - labelWidth
157
+ name.contains(" RIGHT" ) -> 0
158
+ else -> - labelWidth / 2
159
+ }
160
+ point.translate((x * 4 ) + xOffset, y * (caretHeight / 2 ))
161
+ }
162
+ return point
107
163
}
108
164
109
165
/* *
110
166
* Fading label class for displaying XP gain.
111
167
*/
112
168
internal class FadingLabel (initialValue : Int ) : JLabel(if (initialValue == 0) " 0 xp" else " +$initialValue XP" ) {
113
- private lateinit var timer: javax.swing. Timer
169
+ private lateinit var timer: Timer
114
170
115
171
/* *
116
172
* Start fade out animation.
117
173
*/
118
174
fun startFadeOut () {
119
- timer = javax.swing. Timer (100 , null )
175
+ timer = Timer (100 , null )
120
176
timer.addActionListener {
121
177
val newAlpha = max(foreground.alpha - 255 / 10 , 0 )
122
178
if (newAlpha <= 0 ) {
123
179
timer.stop()
124
180
value = 0
125
181
} else {
126
182
foreground =
127
- Color (JBColor .foreground().red, JBColor .foreground().green, JBColor .foreground().blue, newAlpha)
183
+ JBColor (
184
+ Color (
185
+ JBColor .foreground().red,
186
+ JBColor .foreground().green,
187
+ JBColor .foreground().blue,
188
+ newAlpha
189
+ ),
190
+ Color (
191
+ JBColor .foreground().red,
192
+ JBColor .foreground().green,
193
+ JBColor .foreground().blue,
194
+ newAlpha
195
+ )
196
+ )
128
197
}
129
198
}
130
199
timer.start()
@@ -149,4 +218,65 @@ object CodeXPUIManager : CodeXPListener {
149
218
}
150
219
}
151
220
}
221
+
222
+ /* *
223
+ * Create a dialog.
224
+ */
225
+ fun createDialogArea () {
226
+ dialogArea = JPanel ()
227
+ with (dialogArea) {
228
+ layout = BoxLayout (this , BoxLayout .Y_AXIS )
229
+ isVisible = false
230
+ background = JBColor (Color (255 , 255 , 255 , 0 ), Color (255 , 255 , 255 , 0 ))
231
+ isOpaque = false
232
+
233
+ addMouseListener(object : MouseAdapter () {})
234
+ addMouseMotionListener(object : MouseMotionAdapter () {})
235
+ }
236
+
237
+ WindowManager .getInstance()
238
+ .getIdeFrame(ProjectManager .getInstance().openProjects.firstOrNull())?.component?.rootPane?.layeredPane?.let {
239
+ ide = it
240
+ ide.add(dialogArea, JLayeredPane .POPUP_LAYER , 0 )
241
+ } ? : run {
242
+ thisLogger().error(" Could not find IDE frame." )
243
+ }
244
+ }
245
+
246
+ /* *
247
+ * Show the progress window for 3 seconds.
248
+ */
249
+ private fun showDialog (dialog : CodeXPDialog ) {
250
+ dialogTimers[dialog] = Timer (3000 , ActionListener { hideDialog(dialog) })
251
+ dialogTimers[dialog]?.start()
252
+ dialog.show()
253
+
254
+ with (dialogArea) {
255
+ add(dialog.frame, 0 )
256
+ size = Dimension (480 , preferredSize.height)
257
+ location = Point (ide.width / 2 - width / 2 , (ide.height * 0.05 ).toInt())
258
+ revalidate()
259
+ repaint()
260
+ isVisible = true
261
+ }
262
+ }
263
+
264
+ /* *
265
+ * Hide the progress window immediately.
266
+ */
267
+ private fun hideDialog (dialog : CodeXPDialog ) {
268
+ SwingUtilities .invokeLater {
269
+ dialogTimers[dialog]?.stop()
270
+ dialogTimers.remove(dialog)
271
+
272
+ with (dialogArea) {
273
+ remove(dialog.frame)
274
+ size = Dimension (480 , preferredSize.height)
275
+ }
276
+
277
+ if (dialogArea.components.isEmpty()) {
278
+ dialogArea.isVisible = false
279
+ }
280
+ }
281
+ }
152
282
}
0 commit comments