Navigation.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. using PicView.PreLoading;
  2. using System;
  3. using System.IO;
  4. using System.Net;
  5. using System.Threading.Tasks;
  6. using System.Windows.Media;
  7. using System.Windows.Media.Imaging;
  8. using System.Windows.Threading;
  9. using static PicView.ArchiveExtraction;
  10. using static PicView.DeleteFiles;
  11. using static PicView.Error_Handling;
  12. using static PicView.Fields;
  13. using static PicView.FileLists;
  14. using static PicView.Helper;
  15. using static PicView.ImageManager;
  16. using static PicView.Interface;
  17. using static PicView.Resize_and_Zoom;
  18. namespace PicView
  19. {
  20. internal static class Navigation
  21. {
  22. /// <summary>
  23. /// Loads a picture from a given file path and does extra error checking
  24. /// </summary>
  25. /// <param name="path"></param>
  26. internal static async void Pic(string path)
  27. {
  28. // Set Loading
  29. mainWindow.Title = mainWindow.Bar.Text = Loading;
  30. mainWindow.Bar.ToolTip = Loading;
  31. if (mainWindow.img.Source == null)
  32. AjaxLoadingStart();
  33. // Handle if from web
  34. if (!File.Exists(path))
  35. {
  36. if (Uri.IsWellFormedUriString(path, UriKind.Absolute))
  37. PicWeb(path);
  38. else
  39. Unload();
  40. return;
  41. }
  42. // If count not correct or just started, get values
  43. if (Pics == null)
  44. await GetValues(path);
  45. else if (Pics.Count <= FolderIndex || FolderIndex < 0 || freshStartup)
  46. await GetValues(path);
  47. // If the file is in the same folder, navigate to it. If not, start manual loading procedure.
  48. else if (!string.IsNullOrWhiteSpace(PicPath) && Path.GetDirectoryName(path) != Path.GetDirectoryName(PicPath))
  49. {
  50. // Reset zipped values
  51. if (!string.IsNullOrWhiteSpace(TempZipPath))
  52. {
  53. DeleteTempFiles();
  54. TempZipPath = string.Empty;
  55. RecentFiles.SetZipped(string.Empty, false);
  56. }
  57. // Reset old values and get new
  58. ChangeFolder();
  59. await GetValues(path);
  60. }
  61. // If no need to reset values, get index
  62. else if (Pics != null)
  63. FolderIndex = Pics.IndexOf(path);
  64. if (Pics != null)
  65. {
  66. // Fix large archive extraction error
  67. if (Pics.Count == 0)
  68. {
  69. var recovery = await RecoverFailedArchiveAsync();
  70. if (!recovery)
  71. {
  72. ToolTipStyle("Archive could not be processed");
  73. Reload(true);
  74. return;
  75. }
  76. }
  77. }
  78. else
  79. {
  80. Reload(true);
  81. return;
  82. }
  83. if (File.Exists(Pics[FolderIndex]))
  84. {
  85. // Navigate to picture using obtained index
  86. Pic(FolderIndex);
  87. }
  88. else
  89. {
  90. Reload(true);
  91. return;
  92. }
  93. AjaxLoadingEnd();
  94. // Load images for PicGallery if enabled
  95. if (Properties.Settings.Default.PicGallery > 0)
  96. {
  97. if (!PicGalleryLogic.LoadComplete && !PicGalleryLogic.isLoading)
  98. await PicGalleryLogic.Load();
  99. }
  100. if (prevPicResource != null)
  101. prevPicResource = null;
  102. }
  103. /// <summary>
  104. /// Loads image based on overloaded int.
  105. /// Possible out of range error if used inappropriately.
  106. /// </summary>
  107. /// <param name="x"></param>
  108. internal static async void Pic(int x)
  109. {
  110. // Additional error checking
  111. if (Pics.Count < x)
  112. {
  113. if (x == 0)
  114. {
  115. var recovery = await RecoverFailedArchiveAsync();
  116. if (!recovery)
  117. {
  118. ToolTipStyle("Archive could not be processed");
  119. Reload(true);
  120. return;
  121. }
  122. }
  123. else if (!File.Exists(Pics[x]))
  124. PicErrorFix(x);
  125. else
  126. Reload(true);
  127. return;
  128. }
  129. if (x < 0)
  130. {
  131. if (!PicErrorFix(x))
  132. return;
  133. }
  134. // Add "pic" as local variable used for the image.
  135. // Use the Load() function load image from memory if available
  136. // if not, it will be null
  137. BitmapSource pic = Preloader.Load(Pics[x]);
  138. if (pic == null)
  139. {
  140. mainWindow.Title = mainWindow.Bar.Text = Loading;
  141. mainWindow.Bar.ToolTip = Loading;
  142. var size = ImageSize(Pics[x]);
  143. if (size.HasValue)
  144. ZoomFit(size.Value.Width, size.Value.Height);
  145. ImageSource thumb;
  146. if (picGallery != null)
  147. {
  148. if (x < picGallery.Container.Children.Count && picGallery.Container.Children.Count == Pics.Count)
  149. {
  150. var y = picGallery.Container.Children[x] as UserControls.PicGalleryItem;
  151. thumb = y.img.Source;
  152. }
  153. else thumb = GetBitmapSourceThumb(Pics[x]);
  154. }
  155. else
  156. thumb = GetBitmapSourceThumb(Pics[x]);
  157. if (thumb != null)
  158. mainWindow.img.Source = thumb;
  159. // Dissallow changing image while loading
  160. canNavigate = false;
  161. if (freshStartup)
  162. // Load new value manually
  163. await Task.Run(() => pic = RenderToBitmapSource(Pics[x]));
  164. else
  165. {
  166. if (!Properties.Settings.Default.ShowInterface)
  167. AjaxLoadingStart();
  168. do
  169. {
  170. // Try again while loading?
  171. await Task.Delay(25);
  172. if (x < Pics.Count)
  173. pic = Preloader.Load(Pics[x]);
  174. } while (Preloader.IsLoading);
  175. }
  176. // If pic is still null, image can't be rendered
  177. if (pic == null)
  178. {
  179. if (!PicErrorFix(x))
  180. {
  181. // Fixes error when Skipping to last or first pic
  182. await Task.Run(() => pic = RenderToBitmapSource(Pics[x]));
  183. if (pic == null)
  184. Reload(true);
  185. //return;
  186. }
  187. }
  188. }
  189. else
  190. ZoomFit(pic.PixelWidth, pic.PixelHeight);
  191. // Show the image! :)
  192. mainWindow.img.Source = pic;
  193. // Scroll to top if scroll enabled
  194. if (IsScrollEnabled)
  195. mainWindow.Scroller.ScrollToTop();
  196. //// Prevent picture from being flipped if previous is
  197. //if (Flipped)
  198. // Flip();
  199. // Update values
  200. canNavigate = true;
  201. var titleString = TitleString(pic.PixelWidth, pic.PixelHeight, x);
  202. mainWindow.Title = titleString[0];
  203. mainWindow.Bar.Text = titleString[1];
  204. mainWindow.Bar.ToolTip = titleString[2];
  205. PicPath = Pics[x];
  206. FolderIndex = x;
  207. AjaxLoadingEnd();
  208. Progress(x, Pics.Count);
  209. if (picGallery != null)
  210. {
  211. if (!freshStartup)
  212. if (PicGalleryLogic.LoadComplete)
  213. PicGalleryLogic.ScrollTo();
  214. //if (x < picGallery.Container.Children.Count)
  215. //{
  216. // var item = picGallery.Container.Children[x] as PicGalleryItem;
  217. // item.Setselected(true);
  218. // var y = reverse ? x - 1 : x + 1;
  219. // var previtem = picGallery.Container.Children[y] as PicGalleryItem;
  220. // previtem.Setselected(false);
  221. //}
  222. }
  223. // Preload images \\
  224. if (Preloader.StartPreload())
  225. {
  226. Preloader.Add(pic, PicPath);
  227. await Preloader.PreLoad(x);
  228. }
  229. if (!freshStartup)
  230. RecentFiles.Add(Pics[x]);
  231. freshStartup = false;
  232. }
  233. /// <summary>
  234. /// Load a picture from a prepared bitmap
  235. /// </summary>
  236. /// <param name="pic"></param>
  237. /// <param name="imageName"></param>
  238. internal static void Pic(BitmapSource pic, string imageName)
  239. {
  240. Unload();
  241. if (IsScrollEnabled)
  242. mainWindow.Scroller.ScrollToTop();
  243. mainWindow.img.Source = pic;
  244. ZoomFit(pic.PixelWidth, pic.PixelHeight);
  245. CloseToolTipStyle();
  246. var titleString = TitleString(pic.PixelWidth, pic.PixelHeight, imageName);
  247. mainWindow.Title = titleString[0];
  248. mainWindow.Bar.Text = titleString[1];
  249. mainWindow.Bar.ToolTip = titleString[1];
  250. NoProgress();
  251. PicPath = string.Empty;
  252. canNavigate = false;
  253. }
  254. /// <summary>
  255. /// Goes to next, previous, first or last file in folder
  256. /// </summary>
  257. /// <param name="next">Whether it's forward or not</param>
  258. /// <param name="end">Whether to go to last or first,
  259. /// depending on the next value</param>
  260. internal static void Pic(bool next = true, bool end = false)
  261. {
  262. // Exit if not intended to change picture
  263. if (!canNavigate)
  264. return;
  265. // .. Or browsing PicGallery
  266. if (picGallery != null)
  267. {
  268. if (Properties.Settings.Default.PicGallery == 1)
  269. if (PicGalleryLogic.IsOpen)
  270. return;
  271. }
  272. // Go to first or last
  273. if (end)
  274. {
  275. FolderIndex = next ? Pics.Count - 1 : 0;
  276. if (Pics.Count > 20)
  277. {
  278. PreloadCount = 4;
  279. Preloader.Clear();
  280. }
  281. }
  282. // Go to next or previous
  283. else
  284. {
  285. if (next)
  286. {
  287. // loop next
  288. if (Properties.Settings.Default.Looping)
  289. {
  290. FolderIndex = FolderIndex == Pics.Count - 1 ? 0 : FolderIndex + 1;
  291. }
  292. else
  293. {
  294. // Go to next if able
  295. if (FolderIndex + 1 == Pics.Count)
  296. return;
  297. FolderIndex++;
  298. }
  299. PreloadCount++;
  300. reverse = false;
  301. }
  302. else
  303. {
  304. // Loop prev
  305. if (Properties.Settings.Default.Looping)
  306. {
  307. FolderIndex = FolderIndex == 0 ? Pics.Count - 1 : FolderIndex - 1;
  308. }
  309. else
  310. {
  311. // Go to prev if able
  312. if (FolderIndex - 1 < 0)
  313. return;
  314. FolderIndex--;
  315. }
  316. PreloadCount--;
  317. reverse = true;
  318. }
  319. }
  320. Pic(FolderIndex);
  321. }
  322. /// <summary>
  323. /// Only load image from preload or thumbnail without resizing
  324. /// </summary>
  325. internal static void FastPic()
  326. {
  327. //await mainWindow.Dispatcher.BeginInvoke((Action)(() =>
  328. //{
  329. // mainWindow.Bar.ToolTip =
  330. // mainWindow.Title =
  331. // mainWindow.Bar.Text = "Image " + (FolderIndex + 1) + " of " + Pics.Count;
  332. // mainWindow.img.Width = xWidth;
  333. // mainWindow.img.Height = xHeight;
  334. // mainWindow.img.Source = Preloader.Contains(Pics[FolderIndex]) ? Preloader.Load(Pics[FolderIndex]) : GetBitmapSourceThumb(Pics[FolderIndex]);
  335. //}));
  336. //Progress(FolderIndex, Pics.Count);
  337. //FastPicRunning = true;
  338. mainWindow.Bar.ToolTip =
  339. mainWindow.Title =
  340. mainWindow.Bar.Text = "Image " + (FolderIndex + 1) + " of " + Pics.Count;
  341. mainWindow.img.Width = xWidth;
  342. mainWindow.img.Height = xHeight;
  343. mainWindow.img.Source = Preloader.Contains(Pics[FolderIndex]) ? Preloader.Load(Pics[FolderIndex]) : GetBitmapSourceThumb(Pics[FolderIndex]);
  344. Progress(FolderIndex, Pics.Count);
  345. //FastPicRunning = true;
  346. }
  347. /// <summary>
  348. /// Update after FastPic() was used
  349. /// </summary>
  350. internal static void FastPicUpdate()
  351. {
  352. //fastPicTimer.Stop();
  353. //FastPicRunning = false;
  354. //if (!Preloader.Contains(Pics[FolderIndex]))
  355. //{
  356. // PreloadCount = 0;
  357. // Preloader.Clear();
  358. //}
  359. Pic(FolderIndex);
  360. }
  361. /// <summary>
  362. /// Attemps to download image and display it
  363. /// </summary>
  364. /// <param name="path"></param>
  365. internal static async void PicWeb(string path)
  366. {
  367. if (ajaxLoading.Opacity != 1)
  368. AjaxLoadingStart();
  369. mainWindow.Bar.Text = Loading;
  370. BitmapSource pic;
  371. try
  372. {
  373. pic = await LoadImageWebAsync(path);
  374. }
  375. catch (Exception)
  376. {
  377. pic = null;
  378. }
  379. if (pic == null)
  380. {
  381. Reload(true);
  382. ToolTipStyle("Unable to load image");
  383. AjaxLoadingEnd();
  384. return;
  385. }
  386. Pic(pic, path);
  387. PicPath = path;
  388. RecentFiles.Add(path);
  389. }
  390. /// <summary>
  391. /// Downloads image from web and returns as BitmapSource
  392. /// </summary>
  393. /// <param name="address"></param>
  394. /// <returns></returns>
  395. internal static async Task<BitmapSource> LoadImageWebAsync(string address)
  396. {
  397. BitmapSource pic = null;
  398. await Task.Run(async () =>
  399. {
  400. var client = new WebClient();
  401. client.DownloadProgressChanged += (sender, e) =>
  402. mainWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
  403. {
  404. mainWindow.Title = mainWindow.Bar.Text = e.BytesReceived + "/" + e.TotalBytesToReceive + ". " + e.ProgressPercentage + "% complete...";
  405. }));
  406. var bytes = await client.DownloadDataTaskAsync(new Uri(address));
  407. var stream = new MemoryStream(bytes);
  408. pic = GetMagickImage(stream);
  409. });
  410. return pic;
  411. }
  412. }
  413. }