MyLocalModItem.xaml.vb 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. Imports System.Windows.Forms
  2. Public Class MyLocalModItem
  3. #Region "基础属性"
  4. Public Uuid As Integer = GetUuid()
  5. 'Logo
  6. Private _Logo As String = ""
  7. Public Property Logo As String
  8. Get
  9. Return _Logo
  10. End Get
  11. Set(value As String)
  12. If _Logo = value OrElse value Is Nothing Then Exit Property
  13. _Logo = value
  14. If ModeDebug AndAlso Not _Logo = PathImage & "Icons/NoIcon.png" Then Log($"[LocalModItem] Mod {Title} 的图标:{value}")
  15. Dim FileAddress = PathTemp & "CompLogo\" & GetHash(_Logo) & ".png"
  16. Try
  17. If _Logo.StartsWithF("http", True) Then
  18. '网络图片
  19. If File.Exists(FileAddress) Then
  20. PathLogo.Source = New MyBitmap(FileAddress)
  21. Else
  22. PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")
  23. RunInNewThread(Sub() LogoLoader(FileAddress), "Comp Logo Loader " & Uuid & "#", ThreadPriority.BelowNormal)
  24. End If
  25. Else
  26. '位图
  27. PathLogo.Source = New MyBitmap(_Logo)
  28. End If
  29. Catch ex As IOException
  30. Log(ex, "加载本地 Mod 图标时读取失败(" & FileAddress & ")")
  31. Catch ex As ArgumentException
  32. '考虑缓存的图片本身可能有误
  33. Log(ex, "可视化本地 Mod 图标失败(" & FileAddress & ")")
  34. Try
  35. File.Delete(FileAddress)
  36. Log("[LocalModItem] 已清理损坏的本地 Mod 图标:" & FileAddress)
  37. Catch exx As Exception
  38. Log(exx, "清理损坏的本地 Mod 图标缓存失败(" & FileAddress & ")", LogLevel.Hint)
  39. End Try
  40. Catch ex As Exception
  41. Log(ex, "加载本地 Mod 图标失败(" & value & ")")
  42. End Try
  43. End Set
  44. End Property
  45. '后台加载 Logo
  46. Private Sub LogoLoader(LocalFileAddress As String)
  47. Dim Retried As Boolean = False
  48. Dim DownloadEnd As String = GetUuid()
  49. RetryStart:
  50. Try
  51. 'CurseForge 图片使用缩略图
  52. Dim Url As String = _Logo
  53. If Url.Contains("/256/256/") AndAlso GetPixelSize(1) <= 1.25 AndAlso Not Retried Then '#3075:部分 Mod 不存在 64x64 图标,所以重试时不再缩小
  54. Url = Url.Replace("/256/256/", "/64/64/")
  55. End If
  56. '下载图片
  57. NetDownload(Url, LocalFileAddress & DownloadEnd, True)
  58. Dim LoadError As Exception = Nothing
  59. RunInUiWait(
  60. Sub()
  61. Try
  62. '在地址更换时取消加载
  63. If LocalFileAddress <> $"{PathTemp}CompLogo\{GetHash(_Logo)}.png" Then Exit Sub
  64. '在完成正常加载后才保存缓存图片
  65. PathLogo.Source = New MyBitmap(LocalFileAddress & DownloadEnd)
  66. Catch ex As Exception
  67. Log(ex, "读取本地 Mod 图标失败(" & LocalFileAddress & ")")
  68. File.Delete(LocalFileAddress & DownloadEnd)
  69. LoadError = ex
  70. End Try
  71. End Sub)
  72. If LoadError IsNot Nothing Then Throw LoadError
  73. If File.Exists(LocalFileAddress) Then
  74. File.Delete(LocalFileAddress & DownloadEnd)
  75. Else
  76. FileIO.FileSystem.MoveFile(LocalFileAddress & DownloadEnd, LocalFileAddress)
  77. End If
  78. Catch ex As Exception
  79. If Not Retried Then
  80. Retried = True
  81. GoTo RetryStart
  82. Else
  83. Log(ex, $"下载本地 Mod 图标失败({_Logo})")
  84. RunInUi(Sub() PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png"))
  85. End If
  86. End Try
  87. End Sub
  88. '标题
  89. Private _Title As String
  90. Public Property Title As String
  91. Get
  92. Return _Title
  93. End Get
  94. Set(value As String)
  95. Dim RawValue = value
  96. Select Case Entry.State
  97. Case McMod.McModState.Fine
  98. LabTitle.TextDecorations = Nothing
  99. Case McMod.McModState.Disabled
  100. LabTitle.TextDecorations = TextDecorations.Strikethrough
  101. Case McMod.McModState.Unavailable
  102. LabTitle.TextDecorations = TextDecorations.Strikethrough
  103. value &= " [错误]"
  104. End Select
  105. If LabTitle.Text = value Then Exit Property
  106. LabTitle.Text = value
  107. _Title = RawValue
  108. End Set
  109. End Property
  110. '副标题
  111. Public Property SubTitle As String
  112. Get
  113. Return If(LabSubtitle?.Text, "")
  114. End Get
  115. Set(value As String)
  116. If LabSubtitle.Text = value Then Exit Property
  117. LabSubtitle.Text = value
  118. LabSubtitle.Visibility = If(value = "", Visibility.Collapsed, Visibility.Visible)
  119. End Set
  120. End Property
  121. '描述
  122. Public Property Description As String
  123. Get
  124. Return LabInfo.Text
  125. End Get
  126. Set(value As String)
  127. If LabInfo.Text = value Then Exit Property
  128. LabInfo.Text = value
  129. End Set
  130. End Property
  131. 'Tag
  132. Public WriteOnly Property Tags As List(Of String)
  133. Set(value As List(Of String))
  134. PanTags.Children.Clear()
  135. PanTags.Visibility = If(value.Any(), Visibility.Visible, Visibility.Collapsed)
  136. For Each TagText In value
  137. Dim NewTag = GetObjectFromXML(
  138. "<Border xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
  139. Background=""#11000000"" Padding=""3,1"" CornerRadius=""3"" Margin=""0,0,3,0""
  140. SnapsToDevicePixels=""True"" UseLayoutRounding=""False"">
  141. <TextBlock Text=""" & TagText & """ Foreground=""#868686"" FontSize=""11"" />
  142. </Border>")
  143. PanTags.Children.Add(NewTag)
  144. Next
  145. End Set
  146. End Property
  147. '相关联的 Mod
  148. Public Property Entry As McMod
  149. Get
  150. Return Tag
  151. End Get
  152. Set(value As McMod)
  153. Tag = value
  154. End Set
  155. End Property
  156. #End Region
  157. #Region "点击与勾选"
  158. '触发点击事件
  159. Public Event Click(sender As Object, e As MouseButtonEventArgs)
  160. Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp
  161. If IsMouseDown Then
  162. RaiseEvent Click(sender, e)
  163. If e.Handled Then Exit Sub
  164. Log("[Control] 按下本地 Mod 列表项:" & LabTitle.Text)
  165. End If
  166. End Sub
  167. '鼠标点击判定
  168. Private IsMouseDown As Boolean = False
  169. Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
  170. If Not IsMouseDirectlyOver Then Exit Sub
  171. IsMouseDown = True
  172. If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = False
  173. End Sub
  174. Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.PreviewMouseLeftButtonUp
  175. IsMouseDown = False
  176. If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = True
  177. End Sub
  178. '滑动选中
  179. Private Shared SwipeStart As Integer, SwipeEnd As Integer
  180. Private Shared Swiping As Boolean = False
  181. Private Shared SwipToState As Boolean '被滑动到的目标应将 Checked 改为此值
  182. Private Sub Button_MouseSwipeStart(sender As Object, e As Object) Handles Me.MouseLeftButtonDown
  183. If Parent Is Nothing Then Exit Sub 'Mod 可能已被删除(#3824)
  184. '开始滑动
  185. Dim Index = CType(Parent, StackPanel).Children.IndexOf(Me)
  186. SwipeStart = Index
  187. SwipeEnd = Index
  188. Swiping = True
  189. SwipToState = Not Checked
  190. FrmVersionMod.CardSelect.IsHitTestVisible = False '暂时禁用下边栏
  191. End Sub
  192. Private Sub Button_MouseSwipe(sender As Object, e As Object) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonUp
  193. If Parent Is Nothing Then Exit Sub 'Mod 可能已被删除(#3824)
  194. '结束滑动
  195. If Mouse.LeftButton <> MouseButtonState.Pressed OrElse Not Swiping Then
  196. Swiping = False
  197. FrmVersionMod.CardSelect.IsHitTestVisible = True
  198. Exit Sub
  199. End If
  200. '计算滑动范围
  201. Dim Index = CType(Parent, StackPanel).Children.IndexOf(Me)
  202. SwipeStart = Math.Min(SwipeStart, Index)
  203. SwipeEnd = Math.Max(SwipeEnd, Index)
  204. '勾选所有范围中的项
  205. If SwipeStart = SwipeEnd Then Exit Sub
  206. For i = SwipeStart To SwipeEnd
  207. Dim Item As MyLocalModItem = CType(Parent, StackPanel).Children(i)
  208. Item.InitLate(Item, e)
  209. Item.Checked = SwipToState
  210. Next
  211. End Sub
  212. '勾选状态
  213. Public Event Check(sender As Object, e As RouteEventArgs)
  214. Public Event Changed(sender As Object, e As RouteEventArgs)
  215. Private _Checked As Boolean = False
  216. Public Property Checked As Boolean
  217. Get
  218. Return _Checked
  219. End Get
  220. Set(value As Boolean)
  221. Try
  222. '触发属性值修改
  223. Dim RawValue = _Checked
  224. If value = _Checked Then Exit Property
  225. _Checked = value
  226. Dim ChangedEventArgs As New RouteEventArgs(False)
  227. If IsInitialized Then
  228. RaiseEvent Changed(Me, ChangedEventArgs)
  229. If ChangedEventArgs.Handled Then
  230. _Checked = RawValue
  231. Exit Property
  232. End If
  233. End If
  234. If value Then
  235. Dim CheckEventArgs As New RouteEventArgs(False)
  236. RaiseEvent Check(Me, CheckEventArgs)
  237. If CheckEventArgs.Handled Then Exit Property
  238. End If
  239. '更改动画
  240. If IsVisibleInForm() Then
  241. Dim Anim As New List(Of AniData)
  242. If Checked Then
  243. '由无变有
  244. Dim Delta = 32 - RectCheck.ActualHeight
  245. Anim.Add(AaHeight(RectCheck, Delta * 0.4, 200,, New AniEaseOutFluent(AniEasePower.Weak)))
  246. Anim.Add(AaHeight(RectCheck, Delta * 0.6, 300,, New AniEaseOutBack(AniEasePower.Weak)))
  247. Anim.Add(AaOpacity(RectCheck, 1 - RectCheck.Opacity, 30))
  248. RectCheck.VerticalAlignment = VerticalAlignment.Center
  249. RectCheck.Margin = New Thickness(-3, 0, 0, 0)
  250. Anim.Add(AaColor(LabTitle, TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush2", "ColorBrush5"), 200))
  251. Else
  252. '由有变无
  253. Anim.Add(AaHeight(RectCheck, -RectCheck.ActualHeight, 120,, New AniEaseInFluent(AniEasePower.Weak)))
  254. Anim.Add(AaOpacity(RectCheck, -RectCheck.Opacity, 70, 40))
  255. RectCheck.VerticalAlignment = VerticalAlignment.Center
  256. Anim.Add(AaColor(LabTitle, TextBlock.ForegroundProperty, If(LabTitle.TextDecorations Is Nothing, "ColorBrush1", "ColorBrushGray4"), 120))
  257. End If
  258. AniStart(Anim, "MyLocalModItem Checked " & Uuid)
  259. Else
  260. '不在窗口上时直接设置
  261. RectCheck.VerticalAlignment = VerticalAlignment.Center
  262. RectCheck.Margin = New Thickness(-3, 0, 0, 0)
  263. If Checked Then
  264. RectCheck.Height = 32
  265. RectCheck.Opacity = 1
  266. LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush2", "ColorBrush5"))
  267. Else
  268. RectCheck.Height = 0
  269. RectCheck.Opacity = 0
  270. LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush1", "ColorBrushGray4"))
  271. End If
  272. AniStop("MyLocalModItem Checked " & Uuid)
  273. End If
  274. Catch ex As Exception
  275. Log(ex, "设置 Checked 失败")
  276. End Try
  277. End Set
  278. End Property
  279. #End Region
  280. #Region "后加载内容"
  281. '右下角状态指示图标
  282. Private ImgState As Image
  283. '指向背景
  284. Private _RectBack As Border = Nothing
  285. Public ReadOnly Property RectBack As Border
  286. Get
  287. If _RectBack Is Nothing Then
  288. Dim Rect As New Border With {
  289. .Name = "RectBack",
  290. .CornerRadius = New CornerRadius(3),
  291. .RenderTransform = New ScaleTransform(0.8, 0.8),
  292. .RenderTransformOrigin = New Point(0.5, 0.5),
  293. .BorderThickness = New Thickness(GetWPFSize(1)),
  294. .SnapsToDevicePixels = True,
  295. .IsHitTestVisible = False,
  296. .Opacity = 0
  297. }
  298. Rect.SetResourceReference(Border.BackgroundProperty, "ColorBrush7")
  299. Rect.SetResourceReference(Border.BorderBrushProperty, "ColorBrush6")
  300. SetColumnSpan(Rect, 999)
  301. SetRowSpan(Rect, 999)
  302. Children.Insert(0, Rect)
  303. _RectBack = Rect
  304. '<!--<Border x:Name = "RectBack" CornerRadius="3" RenderTransformOrigin="0.5,0.5" SnapsToDevicePixels="True"
  305. 'IsHitTestVisible = "False" Opacity="0" BorderThickness="1"
  306. 'Grid.ColumnSpan = "4" Background="{DynamicResource ColorBrush7}" BorderBrush="{DynamicResource ColorBrush6}"/>-->
  307. End If
  308. Return _RectBack
  309. End Get
  310. End Property
  311. '按钮
  312. Public ButtonHandler As Action(Of MyLocalModItem, EventArgs)
  313. Public ButtonStack As FrameworkElement
  314. Private _Buttons As IEnumerable(Of MyIconButton)
  315. Public Property Buttons As IEnumerable(Of MyIconButton)
  316. Get
  317. Return _Buttons
  318. End Get
  319. Set(value As IEnumerable(Of MyIconButton))
  320. _Buttons = value
  321. '移除原 Stack
  322. If ButtonStack IsNot Nothing Then
  323. Children.Remove(ButtonStack)
  324. ButtonStack = Nothing
  325. End If
  326. If Not value.Any() Then Exit Property
  327. '添加新 Stack
  328. ButtonStack = New StackPanel With {.Opacity = 0, .Margin = New Thickness(0, 0, 5, 0), .SnapsToDevicePixels = False, .Orientation = Orientation.Horizontal,
  329. .HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Center, .UseLayoutRounding = False}
  330. SetColumnSpan(ButtonStack, 10) : SetRowSpan(ButtonStack, 10)
  331. '构造按钮
  332. For Each Btn As MyIconButton In value
  333. If Btn.Height.Equals(Double.NaN) Then Btn.Height = 25
  334. If Btn.Width.Equals(Double.NaN) Then Btn.Width = 25
  335. CType(ButtonStack, StackPanel).Children.Add(Btn)
  336. Next
  337. Children.Add(ButtonStack)
  338. End Set
  339. End Property
  340. '勾选条
  341. Private _RectCheck As Border
  342. Public ReadOnly Property RectCheck As Border
  343. Get
  344. If _RectCheck Is Nothing Then
  345. _RectCheck = New Border With {.Width = 5, .Height = If(Checked, Double.NaN, 0), .CornerRadius = New CornerRadius(2, 2, 2, 2),
  346. .VerticalAlignment = If(Checked, VerticalAlignment.Stretch, VerticalAlignment.Center),
  347. .HorizontalAlignment = HorizontalAlignment.Left, .UseLayoutRounding = False, .SnapsToDevicePixels = False,
  348. .Margin = If(Checked, New Thickness(-3, 6, 0, 6), New Thickness(-3, 0, 0, 0))}
  349. _RectCheck.SetResourceReference(Border.BackgroundProperty, "ColorBrush3")
  350. SetRowSpan(_RectCheck, 10)
  351. Children.Add(_RectCheck)
  352. End If
  353. Return _RectCheck
  354. End Get
  355. End Property
  356. #End Region
  357. Public Sub Refresh()
  358. RunInUi(
  359. Sub()
  360. '更新
  361. If Entry.CanUpdate Then
  362. BtnUpdate.Visibility = Visibility.Visible
  363. Dim CurrentName = Entry.CompFile.FileName.Replace(".jar", "")
  364. Dim NewestName = Entry.UpdateFile.FileName.Replace(".jar", "")
  365. '简化名称对比
  366. Dim CurrentSegs = CurrentName.Split("-"c).ToList()
  367. Dim NewestSegs = NewestName.Split("-"c).ToList()
  368. Dim Shortened As Boolean = False
  369. For Each Seg In CurrentSegs.ToList()
  370. If Not NewestSegs.Contains(Seg) Then Continue For
  371. CurrentSegs.Remove(Seg)
  372. NewestSegs.Remove(Seg)
  373. Shortened = True
  374. Next
  375. If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then
  376. CurrentName = Join(CurrentSegs, "-")
  377. NewestName = Join(NewestSegs, "-")
  378. Entry._Version = CurrentName '使用网络信息作为显示的版本号
  379. End If
  380. BtnUpdate.ToolTip = $"当前版本:{CurrentName} ({Entry.CompFile.ReleaseDate:yyyy/MM/dd HH:mm:ss}){vbCrLf}最新版本:{NewestName} ({Entry.UpdateFile.ReleaseDate:yyyy/MM/dd HH:mm:ss}){vbCrLf}点击以更新,右键查看更新日志。"
  381. Else
  382. BtnUpdate.Visibility = Visibility.Collapsed
  383. End If
  384. '标题
  385. If Entry.Comp Is Nothing Then
  386. Title = Entry.Name
  387. SubTitle = If(Entry.Version Is Nothing, "", " | " & Entry.Version)
  388. Else
  389. Dim Titles = Entry.Comp.GetControlTitle(False)
  390. Title = Titles.Key
  391. SubTitle = Titles.Value & If(Entry.Version Is Nothing, "", " | " & Entry.Version)
  392. End If
  393. If Checked Then
  394. LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush2", "ColorBrush5"))
  395. Else
  396. LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush1", "ColorBrushGray4"))
  397. End If
  398. '描述
  399. Dim NewDescription As String
  400. Select Case Entry.State
  401. Case McMod.McModState.Fine
  402. NewDescription = GetFileNameWithoutExtentionFromPath(Entry.Path)
  403. Case McMod.McModState.Disabled
  404. NewDescription = GetFileNameWithoutExtentionFromPath(Entry.Path.Replace(".disabled", "").Replace(".old", ""))
  405. Case Else 'McMod.McModState.Unavailable
  406. NewDescription = GetFileNameFromPath(Entry.Path)
  407. End Select
  408. If Entry.Comp IsNot Nothing Then
  409. NewDescription += ": " & Entry.Comp.Description.Replace(vbCr, "").Replace(vbLf, "")
  410. ElseIf Entry.Description IsNot Nothing Then
  411. NewDescription += ": " & Entry.Description.Replace(vbCr, "").Replace(vbLf, "")
  412. ElseIf Not Entry.IsFileAvailable Then
  413. NewDescription += ": " & "存在错误,无法获取信息"
  414. End If
  415. Description = NewDescription
  416. '主 Logo
  417. Logo = If(Entry.Comp Is Nothing, PathImage & "Icons/NoIcon.png", Entry.Comp.GetControlLogo())
  418. '图标右下角的 Logo
  419. If Entry.State = McMod.McModState.Fine Then
  420. If ImgState IsNot Nothing Then
  421. Children.Remove(ImgState)
  422. ImgState = Nothing
  423. End If
  424. Else
  425. If ImgState Is Nothing Then
  426. ImgState = New Image With {
  427. .Width = 20, .Height = 20, .Margin = New Thickness(0, 0, -5, -3), .IsHitTestVisible = False,
  428. .HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Bottom
  429. }
  430. RenderOptions.SetBitmapScalingMode(ImgState, BitmapScalingMode.HighQuality)
  431. SetColumn(ImgState, 1) : SetRow(ImgState, 1) : SetRowSpan(ImgState, 2)
  432. Children.Add(ImgState)
  433. '<Image x:Name="ImgState" RenderOptions.BitmapScalingMode="HighQuality" Width="16" Height="16" Margin="0,0,-3,-1"
  434. ' Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" IsHitTestVisible="False"
  435. ' HorizontalAlignment="Right" VerticalAlignment="Bottom"
  436. ' Source="/Images/Icons/Unavailable.png" />
  437. End If
  438. ImgState.Source = New MyBitmap(PathImage & $"Icons/{Entry.State}.png")
  439. End If
  440. '标签
  441. If Entry.Comp IsNot Nothing Then Tags = Entry.Comp.Tags
  442. End Sub)
  443. End Sub
  444. Public Sub RefreshColor(sender As Object, e As EventArgs) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonDown, Me.MouseLeftButtonUp, Me.Changed
  445. InitLate(sender, e)
  446. '触发颜色动画
  447. Dim Time As Integer = If(IsMouseOver, 120, 180)
  448. Dim Ani As New List(Of AniData)
  449. 'ButtonStack
  450. If ButtonStack IsNot Nothing Then
  451. If IsMouseOver Then
  452. Ani.Add(AaOpacity(ButtonStack, 1 - ButtonStack.Opacity, Time * 0.7, Time * 0.3))
  453. Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
  454. 5 + Buttons.Count * 25 - ColumnPaddingRight.Width.Value, Time * 0.3, Time * 0.7))
  455. Else
  456. Ani.Add(AaOpacity(ButtonStack, -ButtonStack.Opacity, Time * 0.4))
  457. Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
  458. 4 - ColumnPaddingRight.Width.Value, Time * 0.4))
  459. End If
  460. End If
  461. 'RectBack
  462. If IsMouseOver OrElse Checked Then
  463. Ani.AddRange({
  464. AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
  465. AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
  466. })
  467. If IsMouseDown Then
  468. Ani.Add(AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
  469. Else
  470. Ani.Add(AaScaleTransform(RectBack, 1 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
  471. End If
  472. Else
  473. Ani.AddRange({
  474. AaOpacity(RectBack, -RectBack.Opacity, Time),
  475. AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
  476. AaScaleTransform(RectBack, -0.196, 1,,, True)
  477. })
  478. End If
  479. AniStart(Ani, "LocalModItem Color " & Uuid)
  480. End Sub
  481. '触发虚拟化内容
  482. Private Sub InitLate(sender As Object, e As EventArgs)
  483. If ButtonHandler IsNot Nothing Then
  484. ButtonHandler(sender, e)
  485. ButtonHandler = Nothing
  486. End If
  487. End Sub
  488. '显示更新日志
  489. Private Sub ShowUpdateLog(sender As Object, e As MouseButtonEventArgs) Handles BtnUpdate.PreviewMouseRightButtonUp
  490. e.Handled = True
  491. Dim CurseForgeUrl As String = Entry.ChangelogUrls.FirstOrDefault(Function(x) x.Contains("curseforge.com"))
  492. Dim ModrinthUrl As String = Entry.ChangelogUrls.FirstOrDefault(Function(x) x.Contains("modrinth.com"))
  493. If CurseForgeUrl Is Nothing OrElse ModrinthUrl Is Nothing Then
  494. OpenWebsite(Entry.ChangelogUrls.First)
  495. Else
  496. Select Case MyMsgBox("要在哪个网站上查看更新日志?", "查看更新日志", "Modrinth", "CurseForge", "取消")
  497. Case 1
  498. OpenWebsite(ModrinthUrl)
  499. Case 2
  500. OpenWebsite(CurseForgeUrl)
  501. End Select
  502. End If
  503. End Sub
  504. '触发更新
  505. Private Sub BtnUpdate_Click(sender As Object, e As EventArgs) Handles BtnUpdate.Click
  506. FrmVersionMod.UpdateMods({Entry})
  507. End Sub
  508. '自适应(#4465)
  509. Private Sub PanTitle_SizeChanged(sender As Object, e As SizeChangedEventArgs) Handles PanTitle.SizeChanged
  510. If ColumnExtend.Width.IsStar AndAlso ColumnExtend.ActualWidth < 0.5 Then
  511. '压缩 Subtitle
  512. ColumnSubtitle.Width = New GridLength(1, GridUnitType.Star)
  513. ColumnExtend.Width = New GridLength(0, GridUnitType.Pixel)
  514. ElseIf Not ColumnExtend.Width.IsStar AndAlso Not LabSubtitle.IsTextTrimmed Then
  515. '向右展开 Subtitle
  516. ColumnSubtitle.Width = GridLength.Auto
  517. ColumnExtend.Width = New GridLength(1, GridUnitType.Star)
  518. End If
  519. End Sub
  520. End Class