Navigation.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  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. }
  101. /// <summary>
  102. /// Loads image based on overloaded int.
  103. /// Possible out of range error if used inappropriately.
  104. /// </summary>
  105. /// <param name="x"></param>
  106. internal static async void Pic(int x)
  107. {
  108. // Additional error checking
  109. if (Pics.Count < x)
  110. {
  111. if (x == 0)
  112. {
  113. var recovery = await RecoverFailedArchiveAsync();
  114. if (!recovery)
  115. {
  116. ToolTipStyle("Archive could not be processed");
  117. Reload(true);
  118. return;
  119. }
  120. }
  121. else if (!File.Exists(Pics[x]))
  122. PicErrorFix(x);
  123. else
  124. Reload(true);
  125. return;
  126. }
  127. if (x < 0)
  128. {
  129. if (!PicErrorFix(x))
  130. return;
  131. }
  132. // Add "pic" as local variable used for the image.
  133. // Use the Load() function load image from memory if available
  134. // if not, it will be null
  135. BitmapSource pic = Preloader.Load(Pics[x]);
  136. if (pic == null)
  137. {
  138. mainWindow.Title = mainWindow.Bar.Text = Loading;
  139. mainWindow.Bar.ToolTip = Loading;
  140. var size = ImageSize(Pics[x]);
  141. if (size.HasValue)
  142. ZoomFit(size.Value.Width, size.Value.Height);
  143. ImageSource thumb;
  144. if (picGallery != null)
  145. {
  146. if (x < picGallery.Container.Children.Count)
  147. {
  148. var y = picGallery.Container.Children[x] as UserControls.PicGalleryItem;
  149. thumb = y.img.Source;
  150. }
  151. else thumb = GetBitmapSourceThumb(Pics[x]);
  152. }
  153. else
  154. thumb = GetBitmapSourceThumb(Pics[x]);
  155. if (thumb != null)
  156. mainWindow.img.Source = thumb;
  157. // Dissallow changing image while loading
  158. canNavigate = false;
  159. if (freshStartup)
  160. // Load new value manually
  161. await Task.Run(() => pic = RenderToBitmapSource(Pics[x]));
  162. else
  163. {
  164. if (!Properties.Settings.Default.ShowInterface)
  165. AjaxLoadingStart();
  166. do
  167. {
  168. // Try again while loading?
  169. await Task.Delay(25);
  170. if (x < Pics.Count)
  171. pic = Preloader.Load(Pics[x]);
  172. } while (Preloader.IsLoading);
  173. }
  174. // If pic is still null, image can't be rendered
  175. if (pic == null)
  176. {
  177. if (!PicErrorFix(x))
  178. {
  179. // Fixes error when Skipping to last or first pic
  180. await Task.Run(() => pic = RenderToBitmapSource(Pics[x]));
  181. if (pic == null)
  182. Reload(true);
  183. }
  184. }
  185. }
  186. else
  187. ZoomFit(pic.PixelWidth, pic.PixelHeight);
  188. // Show the image! :)
  189. mainWindow.img.Source = pic;
  190. // Scroll to top if scroll enabled
  191. if (IsScrollEnabled)
  192. mainWindow.Scroller.ScrollToTop();
  193. //// Prevent picture from being flipped if previous is
  194. //if (Flipped)
  195. // Flip();
  196. // Update values
  197. canNavigate = true;
  198. var titleString = TitleString(pic.PixelWidth, pic.PixelHeight, x);
  199. mainWindow.Title = titleString[0];
  200. mainWindow.Bar.Text = titleString[1];
  201. mainWindow.Bar.ToolTip = titleString[2];
  202. PicPath = Pics[x];
  203. FolderIndex = x;
  204. AjaxLoadingEnd();
  205. Progress(x, Pics.Count);
  206. if (picGallery != null)
  207. {
  208. if (freshStartup)
  209. {
  210. if (PicGalleryLogic.LoadComplete)
  211. PicGalleryLogic.ScrollTo();
  212. }
  213. else
  214. PicGalleryLogic.ScrollTo(reverse);
  215. //if (x < picGallery.Container.Children.Count)
  216. //{
  217. // var item = picGallery.Container.Children[x] as PicGalleryItem;
  218. // item.Setselected(true);
  219. // var y = reverse ? x - 1 : x + 1;
  220. // var previtem = picGallery.Container.Children[y] as PicGalleryItem;
  221. // previtem.Setselected(false);
  222. //}
  223. }
  224. // Preload images \\
  225. if (Preloader.StartPreload())
  226. await Preloader.PreLoad(x);
  227. if (!freshStartup)
  228. RecentFiles.Add(Pics[x]);
  229. freshStartup = false;
  230. }
  231. /// <summary>
  232. /// Load a picture from a prepared bitmap
  233. /// </summary>
  234. /// <param name="pic"></param>
  235. /// <param name="imageName"></param>
  236. internal static void Pic(BitmapSource pic, string imageName)
  237. {
  238. Unload();
  239. if (IsScrollEnabled)
  240. mainWindow.Scroller.ScrollToTop();
  241. mainWindow.img.Source = pic;
  242. ZoomFit(pic.PixelWidth, pic.PixelHeight);
  243. CloseToolTipStyle();
  244. var titleString = TitleString(pic.PixelWidth, pic.PixelHeight, imageName);
  245. mainWindow.Title = titleString[0];
  246. mainWindow.Bar.Text = titleString[1];
  247. mainWindow.Bar.ToolTip = titleString[1];
  248. NoProgress();
  249. PicPath = string.Empty;
  250. canNavigate = false;
  251. }
  252. /// <summary>
  253. /// Goes to next, previous, first or last file in folder
  254. /// </summary>
  255. /// <param name="next">Whether it's forward or not</param>
  256. /// <param name="end">Whether to go to last or first,
  257. /// depending on the next value</param>
  258. internal static void Pic(bool next = true, bool end = false)
  259. {
  260. // Exit if not intended to change picture
  261. if (!canNavigate)
  262. return;
  263. // .. Or browsing PicGallery
  264. if (picGallery != null)
  265. {
  266. if (Properties.Settings.Default.PicGallery == 1)
  267. if (PicGalleryLogic.IsOpen)
  268. return;
  269. }
  270. // Go to first or last
  271. if (end)
  272. {
  273. FolderIndex = next ? Pics.Count - 1 : 0;
  274. PreloadCount = 4;
  275. Preloader.Clear();
  276. }
  277. // Go to next or previous
  278. else
  279. {
  280. if (next)
  281. {
  282. // loop next
  283. if (Properties.Settings.Default.Looping)
  284. {
  285. FolderIndex = FolderIndex == Pics.Count - 1 ? 0 : FolderIndex + 1;
  286. }
  287. else
  288. {
  289. // Go to next if able
  290. if (FolderIndex + 1 == Pics.Count)
  291. return;
  292. FolderIndex++;
  293. }
  294. PreloadCount++;
  295. reverse = false;
  296. }
  297. else
  298. {
  299. // Loop prev
  300. if (Properties.Settings.Default.Looping)
  301. {
  302. FolderIndex = FolderIndex == 0 ? Pics.Count - 1 : FolderIndex - 1;
  303. }
  304. else
  305. {
  306. // Go to prev if able
  307. if (FolderIndex - 1 < 0)
  308. return;
  309. FolderIndex--;
  310. }
  311. PreloadCount--;
  312. reverse = true;
  313. }
  314. }
  315. Pic(FolderIndex);
  316. }
  317. /// <summary>
  318. /// Only load image from preload or thumbnail without resizing
  319. /// </summary>
  320. internal static void FastPic()
  321. {
  322. //await mainWindow.Dispatcher.BeginInvoke((Action)(() =>
  323. //{
  324. // mainWindow.Bar.ToolTip =
  325. // mainWindow.Title =
  326. // mainWindow.Bar.Text = "Image " + (FolderIndex + 1) + " of " + Pics.Count;
  327. // mainWindow.img.Width = xWidth;
  328. // mainWindow.img.Height = xHeight;
  329. // mainWindow.img.Source = Preloader.Contains(Pics[FolderIndex]) ? Preloader.Load(Pics[FolderIndex]) : GetBitmapSourceThumb(Pics[FolderIndex]);
  330. //}));
  331. //Progress(FolderIndex, Pics.Count);
  332. //FastPicRunning = true;
  333. mainWindow.Bar.ToolTip =
  334. mainWindow.Title =
  335. mainWindow.Bar.Text = "Image " + (FolderIndex + 1) + " of " + Pics.Count;
  336. mainWindow.img.Width = xWidth;
  337. mainWindow.img.Height = xHeight;
  338. mainWindow.img.Source = Preloader.Contains(Pics[FolderIndex]) ? Preloader.Load(Pics[FolderIndex]) : GetBitmapSourceThumb(Pics[FolderIndex]);
  339. Progress(FolderIndex, Pics.Count);
  340. FastPicRunning = true;
  341. }
  342. /// <summary>
  343. /// Update after FastPic() was used
  344. /// </summary>
  345. internal static void FastPicUpdate()
  346. {
  347. //fastPicTimer.Stop();
  348. FastPicRunning = false;
  349. //if (!Preloader.Contains(Pics[FolderIndex]))
  350. //{
  351. // PreloadCount = 0;
  352. // Preloader.Clear();
  353. //}
  354. Pic(FolderIndex);
  355. }
  356. /// <summary>
  357. /// Attemps to download image and display it
  358. /// </summary>
  359. /// <param name="path"></param>
  360. internal static async void PicWeb(string path)
  361. {
  362. if (ajaxLoading.Opacity != 1)
  363. AjaxLoadingStart();
  364. mainWindow.Bar.Text = Loading;
  365. BitmapSource pic;
  366. try
  367. {
  368. pic = await LoadImageWebAsync(path);
  369. }
  370. catch (Exception)
  371. {
  372. pic = null;
  373. }
  374. if (pic == null)
  375. {
  376. Reload(true);
  377. ToolTipStyle("Unable to load image");
  378. AjaxLoadingEnd();
  379. return;
  380. }
  381. Pic(pic, path);
  382. PicPath = path;
  383. RecentFiles.Add(path);
  384. }
  385. /// <summary>
  386. /// Downloads image from web and returns as BitmapSource
  387. /// </summary>
  388. /// <param name="address"></param>
  389. /// <returns></returns>
  390. internal static async Task<BitmapSource> LoadImageWebAsync(string address)
  391. {
  392. BitmapSource pic = null;
  393. await Task.Run(async () =>
  394. {
  395. var client = new WebClient();
  396. client.DownloadProgressChanged += (sender, e) =>
  397. mainWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
  398. {
  399. mainWindow.Title = mainWindow.Bar.Text = e.BytesReceived + "/" + e.TotalBytesToReceive + ". " + e.ProgressPercentage + "% complete...";
  400. }));
  401. var bytes = await client.DownloadDataTaskAsync(new Uri(address));
  402. var stream = new MemoryStream(bytes);
  403. pic = GetMagickImage(stream);
  404. });
  405. return pic;
  406. }
  407. }
  408. }