summaryrefslogtreecommitdiff
path: root/platform/winrt/gsview/MainWindow.xaml.cs
diff options
context:
space:
mode:
authorMichael Vrhel <michael.vrhel@artifex.com>2014-04-06 21:07:12 -0700
committerMichael Vrhel <michael.vrhel@artifex.com>2014-09-09 16:39:34 -0700
commit75679d3ed3896ac44d6e804345404bc19a8b98c7 (patch)
tree5fa559fe1a93681aa17c0eeed18346f5aac7e1cb /platform/winrt/gsview/MainWindow.xaml.cs
parent7de76c620cbb8f5c03386c23966bd0d62be0d357 (diff)
downloadmupdf-75679d3ed3896ac44d6e804345404bc19a8b98c7.tar.xz
Code toward getting text selection across pages working.
Diffstat (limited to 'platform/winrt/gsview/MainWindow.xaml.cs')
-rw-r--r--platform/winrt/gsview/MainWindow.xaml.cs1345
1 files changed, 1251 insertions, 94 deletions
diff --git a/platform/winrt/gsview/MainWindow.xaml.cs b/platform/winrt/gsview/MainWindow.xaml.cs
index f5629b21..8b953f9c 100644
--- a/platform/winrt/gsview/MainWindow.xaml.cs
+++ b/platform/winrt/gsview/MainWindow.xaml.cs
@@ -19,6 +19,7 @@ using System.IO;
using System.Windows.Xps.Packaging;
using System.Printing;
using System.Windows.Markup;
+using System.Runtime.InteropServices;
enum PDFType_t
{
@@ -130,9 +131,11 @@ static class Constants
public const int SEARCH_BACKWARD = -1;
public const int TEXT_NOT_FOUND = -1;
public const int DEFAULT_GS_RES = 300;
+ public const int DISPATCH_TIME = 50;
+ public const int SCROLL_STEP = 10;
+ public const int SCROLL_EDGE_BUFFER = 90;
}
-
public static class DocumentTypes
{
public const string PDF = "Portable Document Format";
@@ -150,6 +153,12 @@ namespace gsview
/// </summary>
///
+ public struct ContextMenu_t
+ {
+ public int page_num;
+ public Point mouse_position;
+ }
+
public struct thumb_t
{
public int page_num;
@@ -166,32 +175,36 @@ namespace gsview
public int num_rects;
}
+ public struct textSelectInfo_t
+ {
+ public int pagenum;
+ public bool first_line_full;
+ public bool last_line_full;
+ }
+
public partial class MainWindow : Window
{
mudocument mu_doc;
public Pages m_docPages;
+ List<textSelectInfo_t> m_textSelect;
List<DocPage> m_thumbnails;
List<List<RectList>> m_page_link_list = null;
- int m_contents_size;
- int m_content_item;
- List<RectList> m_text_list = null;
- private int m_rectlist_page;
- private List<ContentEntry> m_content_list;
+ IList<RectList> m_text_list;
+ public List<LinesText> m_lineptrs = null;
+ public List<BlocksText> m_textptrs = null;
+ List<Boolean> m_textset = null;
private bool m_file_open;
private int m_currpage;
private int m_searchpage;
private int m_num_pages;
private bool m_init_done;
private bool m_links_on;
- private int m_search_rect_count;
- String m_textcolor = "#402572AC";
+ String m_textsearchcolor = "#4072AC25";
+ String m_textselectcolor = "#402572AC";
+ String m_regionselect = "#00FFFFFF";
+ //String m_regionselect = "#FFFF0000"; /* Debug */
String m_linkcolor = "#40AC7225";
- RenderingStatus_t m_ren_status;
- private bool m_insearch;
- private bool m_search_active;
- private bool m_handlingzoom;
private bool m_have_thumbs;
- private bool m_have_contents;
double m_doczoom;
ghostsharp m_ghostscript;
String m_currfile;
@@ -200,7 +213,6 @@ namespace gsview
gsOutput m_gsoutput;
Convert m_convertwin;
Password m_password = null;
- bool m_zoomhandled;
BackgroundWorker m_thumbworker = null;
BackgroundWorker m_textsearch = null;
BackgroundWorker m_linksearch = null;
@@ -208,11 +220,15 @@ namespace gsview
Info m_infowindow;
OutputIntent m_outputintents;
Selection m_selection;
- private Point startPoint;
- private Rectangle rect;
String m_prevsearch = null;
int m_numpagesvisible;
bool m_clipboardset;
+ bool m_doscroll;
+ bool m_intxtselect;
+ bool m_textselected;
+ System.Windows.Threading.DispatcherTimer m_dispatcherTimer = null;
+ double m_lastY;
+ double m_maxY;
public MainWindow()
{
@@ -226,6 +242,9 @@ namespace gsview
{
m_docPages = new Pages();
m_thumbnails = new List<DocPage>();
+ m_lineptrs = new List<LinesText>();
+ m_textptrs = new List<BlocksText>();
+ m_textset = new List<Boolean>();
m_ghostscript = new ghostsharp();
m_ghostscript.gsUpdateMain += new ghostsharp.gsCallBackMain(gsProgress);
m_gsoutput = new gsOutput();
@@ -236,7 +255,7 @@ namespace gsview
m_convertwin = null;
m_selection = null;
xaml_ZoomSlider.AddHandler(MouseLeftButtonUpEvent, new MouseButtonEventHandler(ZoomReleased), true);
-
+
mxaml_BackPage.Opacity = 0.5;
mxaml_Contents.Opacity = 0.5;
mxaml_currPage.Opacity = 0.5;
@@ -290,7 +309,7 @@ namespace gsview
private status_t CleanUp()
{
m_init_done = false;
-
+ this.Cursor = System.Windows.Input.Cursors.Arrow;
/* Collapse this stuff since it is going to be released */
xaml_ThumbGrid.Visibility = System.Windows.Visibility.Collapsed;
xaml_ContentGrid.Visibility = System.Windows.Visibility.Collapsed;
@@ -298,8 +317,16 @@ namespace gsview
/* Clear out everything */
if (m_docPages != null && m_docPages.Count > 0)
m_docPages.Clear();
+ if (m_textSelect != null)
+ m_textSelect.Clear();
+ if (m_textset != null)
+ m_textset.Clear();
+ if (m_lineptrs != null && m_lineptrs.Count > 0)
+ m_lineptrs.Clear();
if (m_thumbnails != null && m_thumbnails.Count > 0)
m_thumbnails.Clear();
+ if (m_textptrs != null && m_textptrs.Count > 0)
+ m_textptrs.Clear();
if (m_page_link_list != null && m_page_link_list.Count > 0)
{
m_page_link_list.Clear();
@@ -332,21 +359,19 @@ namespace gsview
m_have_thumbs = false;
m_file_open = false;
- m_insearch = false;
- m_search_active = false;
m_num_pages = -1;
- m_search_rect_count = 0;
m_links_on = false;
- m_rectlist_page = -1;
m_doczoom = 1.0;
m_isXPS = false;
- m_zoomhandled = false;
xaml_CancelThumb.IsEnabled = true;
m_currpage = 0;
m_document_type = DocumentTypes.UNKNOWN;
EnabletoPDF();
m_numpagesvisible = 3;
m_clipboardset = false;
+ m_doscroll = false;
+ m_intxtselect = false;
+ m_textselected = false;
return result;
}
@@ -405,13 +430,13 @@ namespace gsview
* they want */
if (m_ghostscript.GetStatus() != gsStatus.GS_READY)
{
- ShowMessage(NotifyType_t.MESS_STATUS, "GS busy. Cancel to open new file.");
+ ShowMessage(NotifyType_t.MESS_STATUS, "GS busy. Cancel to open new file.");
return;
}
if (m_ghostprint != null && m_ghostprint.IsBusy())
{
- ShowMessage(NotifyType_t.MESS_STATUS, "Let printing complete");
+ ShowMessage(NotifyType_t.MESS_STATUS, "Let printing complete");
return;
}
@@ -430,25 +455,25 @@ namespace gsview
string extension = System.IO.Path.GetExtension(dlg.FileName);
/* We are doing this based on the extension but like should do
* it based upon the content */
- switch(extension.ToUpper())
+ switch (extension.ToUpper())
{
case ".PS":
- m_document_type = DocumentTypes.PS;
+ m_document_type = DocumentTypes.PS;
break;
case ".EPS":
- m_document_type = DocumentTypes.EPS;
+ m_document_type = DocumentTypes.EPS;
break;
case ".XPS":
- m_document_type = DocumentTypes.XPS;
+ m_document_type = DocumentTypes.XPS;
break;
case ".PDF":
- m_document_type = DocumentTypes.PDF;
+ m_document_type = DocumentTypes.PDF;
break;
case ".CBZ":
- m_document_type = DocumentTypes.CBZ;
+ m_document_type = DocumentTypes.CBZ;
break;
default:
- m_document_type = DocumentTypes.UNKNOWN;
+ m_document_type = DocumentTypes.UNKNOWN;
break;
}
if (extension.ToUpper() == ".PS" || extension.ToUpper() == ".EPS")
@@ -549,6 +574,10 @@ namespace gsview
doc_page.Content = Page_Content_t.DUMMY;
doc_page.TextBox = null;
doc_page.LinkBox = null;
+ doc_page.SelHeight = 0;
+ doc_page.SelWidth = 0;
+ doc_page.SelX = 0;
+ doc_page.SelY = 0;
return doc_page;
}
@@ -562,6 +591,9 @@ namespace gsview
m_docPages.Add(InitDocPage());
m_docPages[k].PageNum = k;
m_thumbnails.Add(InitDocPage());
+ m_textptrs.Add(new BlocksText());
+ m_lineptrs.Add(new LinesText());
+ m_textset.Add(false);
}
/* Do the first few full res pages */
@@ -577,15 +609,24 @@ namespace gsview
try
{
Byte[] bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4];
+ BlocksText charlist = null;
Task<int> ren_task =
- new Task<int>(() => mu_doc.RenderPage(k, bitmap, (int)ras_size.X, (int)ras_size.Y, scale_factor, false, true));
+ new Task<int>(() => mu_doc.RenderPage(k, bitmap,
+ (int)ras_size.X, (int)ras_size.Y, scale_factor,
+ false, true, !(m_textset[k]), out charlist));
ren_task.Start();
await ren_task.ContinueWith((antecedent) =>
{
status_t code = (status_t)ren_task.Result;
if (code == status_t.S_ISOK)
- UpdatePage(k, bitmap, ras_size, Page_Content_t.FULL_RESOLUTION, 1.0);
+ {
+ m_textset[k] = true;
+ m_textptrs[k] = charlist;
+ m_docPages[k].TextBlocks = charlist;
+ UpdatePage(k, bitmap, ras_size,
+ Page_Content_t.FULL_RESOLUTION, 1.0);
+ }
}, TaskScheduler.FromCurrentSynchronizationContext());
}
catch (OutOfMemoryException e)
@@ -597,6 +638,7 @@ namespace gsview
}
}
m_init_done = true;
+ m_currpage = 0;
xaml_PageList.ItemsSource = m_docPages;
}
@@ -715,8 +757,10 @@ namespace gsview
if (found != null)
{
var Item = (DocPage)found;
- RenderRange(Item.PageNum, false);
+ if (!(m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled == true))
+ RenderRange(Item.PageNum, false);
}
+ e.Handled = true;
return;
}
}
@@ -725,7 +769,7 @@ namespace gsview
/* Render +/- the look ahead from where we are if blank page is present */
async private void RenderRange(int new_page, bool scrollto)
{
- int range = (int) Math.Ceiling(((double) m_numpagesvisible - 1.0) / 2.0);
+ int range = (int)Math.Ceiling(((double)m_numpagesvisible - 1.0) / 2.0);
for (int k = new_page - range; k <= new_page + range + 1; k++)
{
@@ -738,15 +782,22 @@ namespace gsview
{
Point ras_size;
double scale_factor = m_doczoom;
+ /* To avoid multiple page renderings on top of one
+ * another with scroll changes mark this as being
+ * full resolution */
+ m_docPages[k].Content = Page_Content_t.FULL_RESOLUTION;
if (ComputePageSize(k, scale_factor, out ras_size) == status_t.S_ISOK)
{
try
{
Byte[] bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4];
+ BlocksText charlist = null;
Task<int> ren_task =
- new Task<int>(() => mu_doc.RenderPage(k, bitmap, (int)ras_size.X, (int)ras_size.Y, scale_factor, false, true));
+ new Task<int>(() => mu_doc.RenderPage(k, bitmap,
+ (int)ras_size.X, (int)ras_size.Y, scale_factor,
+ false, true, !(m_textset[k]), out charlist));
ren_task.Start();
await ren_task.ContinueWith((antecedent) =>
{
@@ -765,10 +816,35 @@ namespace gsview
{
m_docPages[k].LinkBox = null;
}
- UpdatePage(k, bitmap, ras_size, Page_Content_t.FULL_RESOLUTION, m_doczoom);
- m_docPages[k].PageRefresh();
+ if (!(m_textset[k]) && charlist != null)
+ {
+ m_textptrs[k] = charlist;
+ if (scale_factor != 1.0)
+ ScaleTextBlocks(k, scale_factor);
+ m_docPages[k].TextBlocks = m_textptrs[k];
+ m_textset[k] = true;
+ }
+ else
+ {
+ /* We had to rerender due to scale */
+ if (m_textptrs[k] != null)
+ {
+ ScaleTextBlocks(k, scale_factor);
+ m_docPages[k].TextBlocks = m_textptrs[k];
+ }
+ if (m_lineptrs[k] != null)
+ {
+ ScaleTextLines(k, scale_factor);
+ m_docPages[k].SelectedLines = m_lineptrs[k];
+ }
+ }
+ UpdatePage(k, bitmap, ras_size,
+ Page_Content_t.FULL_RESOLUTION, m_doczoom);
if (k == new_page && scrollto)
+ {
+ m_doscroll = true;
xaml_PageList.ScrollIntoView(m_docPages[k]);
+ }
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
@@ -784,7 +860,15 @@ namespace gsview
/* We did not have to render the page but we may need to
* scroll to it */
if (k == new_page && scrollto)
+ {
+ m_doscroll = true;
xaml_PageList.ScrollIntoView(m_docPages[k]);
+ }
+ /*
+ if (k == new_page && m_docPages[k].TextBlocks == null)
+ {
+ m_docPages[k].TextBlocks = m_textptrs[k];
+ } */
}
}
}
@@ -804,6 +888,15 @@ namespace gsview
return rect.Contains(bounds2.TopLeft) || rect.Contains(bounds2.BottomRight);
}
+ /* Avoids the next page jumping into view when touched by mouse */
+ private void AvoidScrollIntoView(object sender, RequestBringIntoViewEventArgs e)
+ {
+ if (!m_doscroll)
+ e.Handled = true;
+ else
+ m_doscroll = false;
+ }
+
private void ReleasePages(int old_page, int new_page, int range)
{
if (old_page == new_page) return;
@@ -826,7 +919,7 @@ namespace gsview
{
/* See what is there now */
var doc_page = m_docPages[page_num];
- if (doc_page.Content == Page_Content_t.THUMBNAIL &&
+ if (doc_page.Content == Page_Content_t.THUMBNAIL &&
doc_page.Zoom == m_doczoom) return;
if (m_thumbnails.Count > page_num)
@@ -940,7 +1033,7 @@ namespace gsview
xaml_DistillName.FontWeight = FontWeights.Bold;
xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible;
}
- }
+ }
else
PrintXPS(m_currfile);
}
@@ -974,8 +1067,8 @@ namespace gsview
}
else
{
- xaml_PrintProgress.Value =
- 100.0 * (double) Information.Page / (double)m_num_pages;
+ xaml_PrintProgress.Value =
+ 100.0 * (double)Information.Page / (double)m_num_pages;
}
}
@@ -1017,7 +1110,7 @@ namespace gsview
{
if (m_ghostscript.GetStatus() != gsStatus.GS_READY)
{
- ShowMessage(NotifyType_t.MESS_STATUS, "GS busy");
+ ShowMessage(NotifyType_t.MESS_STATUS, "GS busy");
return;
}
@@ -1057,8 +1150,8 @@ namespace gsview
* selection of pages is continuous. This is done by
* looking at the first one in the list and the last one
* in the list and checking the length */
- SelectPage lastpage = (SelectPage) pages[pages.Count -1];
- SelectPage firstpage = (SelectPage) pages[0];
+ SelectPage lastpage = (SelectPage)pages[pages.Count - 1];
+ SelectPage firstpage = (SelectPage)pages[0];
int temp = lastpage.Page - firstpage.Page + 1;
if (temp == pages.Count)
{
@@ -1074,7 +1167,7 @@ namespace gsview
* by page.*/
pages_selected = pages;
multi_page_needed = true; /* need to put in separate outputs */
- }
+ }
}
xaml_DistillProgress.Value = 0;
if (m_ghostscript.Convert(m_currfile, options,
@@ -1136,7 +1229,7 @@ namespace gsview
}
}
-#region Zoom Control
+ #region Zoom Control
private void ZoomOut(object sender, RoutedEventArgs e)
{
if (!m_init_done)
@@ -1189,6 +1282,7 @@ namespace gsview
/* If the zoom is not equalto 1 then set the zoom to 1 and scoll to this page */
private void PageDoubleClick(object sender, MouseButtonEventArgs e)
{
+ return; /* Disable this for now */
if (m_doczoom != 1.0)
{
m_doczoom = 1.0;
@@ -1207,7 +1301,7 @@ namespace gsview
var desired_zoom = mxaml_Zoomsize.Text;
try
{
- double zoom = (double) System.Convert.ToInt32(desired_zoom) / 100.0;
+ double zoom = (double)System.Convert.ToInt32(desired_zoom) / 100.0;
if (zoom > Constants.ZOOM_MAX)
zoom = Constants.ZOOM_MAX;
if (zoom < Constants.ZOOM_MIN)
@@ -1227,9 +1321,9 @@ namespace gsview
}
}
-#endregion Zoom Control
+ #endregion Zoom Control
-#region Thumb Rendering
+ #region Thumb Rendering
void SetThumbInit(int page_num, Byte[] bitmap, Point ras_size, double zoom_in)
{
/* Two jobs. Store the thumb and possibly update the full page */
@@ -1276,8 +1370,12 @@ namespace gsview
try
{
bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4];
+ BlocksText charlist;
+
/* Synchronous call on our background thread */
- code = (status_t)mu_doc.RenderPage(k, bitmap, (int)ras_size.X, (int)ras_size.Y, scale_factor, false, false);
+ code = (status_t)mu_doc.RenderPage(k, bitmap, (int)ras_size.X,
+ (int)ras_size.Y, scale_factor, false, false, false,
+ out charlist);
}
catch (OutOfMemoryException em)
{
@@ -1319,8 +1417,6 @@ namespace gsview
xaml_ThumbProgress.Value = e.ProgressPercentage;
SetThumbInit(thumb.page_num, thumb.bitmap, thumb.size, 1.0);
- m_docPages[thumb.page_num].PageRefresh();
- m_thumbnails[thumb.page_num].PageRefresh();
}
private void RenderThumbs()
@@ -1346,9 +1442,9 @@ namespace gsview
ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message);
}
}
-#endregion Thumb Rendering
+ #endregion Thumb Rendering
-#region Copy Paste
+ #region Copy Paste
/* Copy the current page as a bmp to the clipboard this is done at the
* current resolution */
private void CopyPage(object sender, RoutedEventArgs e)
@@ -1365,9 +1461,9 @@ namespace gsview
{
var menu = (System.Windows.Controls.MenuItem)sender;
- String tag = (String) menu.Tag;
+ String tag = (String)menu.Tag;
- if (!m_clipboardset || !System.Windows.Clipboard.ContainsImage() ||
+ if (!m_clipboardset || !System.Windows.Clipboard.ContainsImage() ||
!m_init_done)
return;
var bitmap = System.Windows.Clipboard.GetImage();
@@ -1419,9 +1515,9 @@ namespace gsview
encoder.Save(stream);
}
}
-#endregion Copy Paste
+ #endregion Copy Paste
-#region SaveAs
+ #region SaveAs
String CreatePDFXA(Save_Type_t type)
{
Byte[] Resource;
@@ -1517,7 +1613,7 @@ namespace gsview
if (m_ghostscript.Convert(m_currfile, options,
Enum.GetName(typeof(gsDevice_t), gsDevice_t.pdfwrite),
dlg.FileName, m_num_pages, 300, false, null, -1, -1,
- init_file, null) == gsStatus.GS_BUSY)
+ init_file, null) == gsStatus.GS_BUSY)
{
ShowMessage(NotifyType_t.MESS_STATUS, "GS busy");
return;
@@ -1638,7 +1734,7 @@ namespace gsview
{
ShowMessage(NotifyType_t.MESS_STATUS, "Set RGB Output Intent ICC Profile");
return;
- }
+ }
SaveFile(Save_Type_t.PDFA1_RGB);
}
@@ -1648,7 +1744,7 @@ namespace gsview
{
ShowMessage(NotifyType_t.MESS_STATUS, "Set CMYK Output Intent ICC Profile");
return;
- }
+ }
SaveFile(Save_Type_t.PDFA1_CMYK);
}
@@ -1658,7 +1754,7 @@ namespace gsview
{
ShowMessage(NotifyType_t.MESS_STATUS, "Set RGB Output Intent ICC Profile");
return;
- }
+ }
SaveFile(Save_Type_t.PDFA2_RGB);
}
@@ -1668,7 +1764,7 @@ namespace gsview
{
ShowMessage(NotifyType_t.MESS_STATUS, "Set CMYK Output Intent ICC Profile");
return;
- }
+ }
SaveFile(Save_Type_t.PDFA2_CMYK);
}
@@ -1680,9 +1776,9 @@ namespace gsview
{
SaveFile(Save_Type_t.XPS);
}
-#endregion SaveAs
+ #endregion SaveAs
-#region Extract
+ #region Extract
private void Extract(Extract_Type_t type)
{
if (m_selection != null || !m_init_done)
@@ -1704,9 +1800,12 @@ namespace gsview
try
{
Byte[] bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4];
+ BlocksText charlist;
Task<int> ren_task =
- new Task<int>(() => mu_doc.RenderPage(page_num, bitmap, (int)ras_size.X, (int)ras_size.Y, zoom, false, true));
+ new Task<int>(() => mu_doc.RenderPage(page_num, bitmap,
+ (int)ras_size.X, (int)ras_size.Y, zoom, false, true,
+ false, out charlist));
ren_task.Start();
await ren_task.ContinueWith((antecedent) =>
{
@@ -1715,8 +1814,8 @@ namespace gsview
{
if (m_selection != null)
{
- int stride = (int) ras_size.X * 4;
- m_selection.xaml_Image.Source = BitmapSource.Create((int) ras_size.X, (int) ras_size.Y, 72, 72, PixelFormats.Pbgra32, BitmapPalettes.Halftone256, bitmap, stride);
+ int stride = (int)ras_size.X * 4;
+ m_selection.xaml_Image.Source = BitmapSource.Create((int)ras_size.X, (int)ras_size.Y, 72, 72, PixelFormats.Pbgra32, BitmapPalettes.Halftone256, bitmap, stride);
m_selection.xaml_Image.Height = (int)ras_size.Y;
m_selection.xaml_Image.Width = (int)ras_size.X;
m_selection.UpdateRect();
@@ -1829,9 +1928,9 @@ namespace gsview
{
m_outputintents.Show();
}
-#endregion Extract
+ #endregion Extract
-#region Search
+ #region Search
/* Search related code */
private void Search(object sender, RoutedEventArgs e)
{
@@ -1866,8 +1965,8 @@ namespace gsview
{
BackgroundWorker worker = sender as BackgroundWorker;
List<object> genericlist = e.Argument as List<object>;
- int direction = (int) genericlist[0];
- String needle = (String) genericlist[1];
+ int direction = (int)genericlist[0];
+ String needle = (String)genericlist[1];
/* To make sure we get the next page or current page during search */
int in_search = (int)genericlist[2];
m_searchpage = m_currpage + direction * in_search;
@@ -1894,7 +1993,7 @@ namespace gsview
results.page_found = m_searchpage;
results.rectangles = new List<Rect>();
- for (int kk = 0; kk < box_count; kk++ )
+ for (int kk = 0; kk < box_count; kk++)
{
Point top_left;
Size size;
@@ -1935,7 +2034,7 @@ namespace gsview
{
/* Nothing found */
xaml_SearchProgress.Value = e.ProgressPercentage;
- }
+ }
else
{
m_text_list = new List<RectList>();
@@ -1948,7 +2047,7 @@ namespace gsview
{
var rect_item = new RectList();
rect_item.Scale = m_doczoom;
- rect_item.Color = m_textcolor;
+ rect_item.Color = m_textsearchcolor;
rect_item.Height = results.rectangles[kk].Height * m_doczoom;
rect_item.Width = results.rectangles[kk].Width * m_doczoom;
rect_item.X = results.rectangles[kk].X * m_doczoom;
@@ -1957,11 +2056,11 @@ namespace gsview
m_text_list.Add(rect_item);
}
m_docPages[results.page_found].TextBox = m_text_list;
- m_docPages[results.page_found].PageRefresh();
+ m_doscroll = true;
xaml_PageList.ScrollIntoView(m_docPages[results.page_found]);
}
}
-
+
private void SearchCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
@@ -1971,7 +2070,7 @@ namespace gsview
}
else
{
- searchResults_t results = (searchResults_t) e.Result;
+ searchResults_t results = (searchResults_t)e.Result;
if (results.done == true)
{
xaml_SearchGrid.Visibility = System.Windows.Visibility.Collapsed;
@@ -1998,7 +2097,6 @@ namespace gsview
if (temp != null)
{
m_docPages[kk].TextBox = null;
- m_docPages[kk].PageRefresh();
}
}
}
@@ -2042,7 +2140,7 @@ namespace gsview
in_text_search = 0;
ClearTextSearch();
}
-
+
if (m_textsearch == null)
{
m_prevsearch = needle;
@@ -2066,9 +2164,9 @@ namespace gsview
ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message);
}
}
-#endregion Search
+ #endregion Search
-#region Link
+ #region Link
private void LinksToggle(object sender, RoutedEventArgs e)
{
if (!m_init_done)
@@ -2117,7 +2215,7 @@ namespace gsview
int type;
int topage;
- mu_doc.GetLinkItem(j, out top_left, out size, out uri,
+ mu_doc.GetLinkItem(j, out top_left, out size, out uri,
out topage, out type);
rectlist.Height = size.Height * m_doczoom;
rectlist.Width = size.Width * m_doczoom;
@@ -2129,7 +2227,7 @@ namespace gsview
rectlist.Scale = m_doczoom;
if (uri != null)
rectlist.Urilink = new Uri(uri);
- rectlist.Type = (Link_t) type;
+ rectlist.Type = (Link_t)type;
links.Add(rectlist);
}
}
@@ -2167,6 +2265,42 @@ namespace gsview
}
m_docPages[pagenum].LinkBox = temp;
}
+ /* Merge these */
+ private void ScaleTextLines(int pagenum, double scale_factor)
+ {
+ var temp = m_lineptrs[pagenum];
+ for (int kk = 0; kk < temp.Count; kk++)
+ {
+ var rect_item = temp[kk];
+ double factor = scale_factor / temp[kk].Scale;
+
+ temp[kk].Height = temp[kk].Height * factor;
+ temp[kk].Width = temp[kk].Width * factor;
+ temp[kk].X = temp[kk].X * factor;
+ temp[kk].Y = temp[kk].Y * factor;
+
+ temp[kk].Scale = scale_factor;
+ }
+ m_lineptrs[pagenum] = temp;
+ }
+
+ private void ScaleTextBlocks(int pagenum, double scale_factor)
+ {
+ var temp = m_textptrs[pagenum];
+ for (int kk = 0; kk < temp.Count; kk++)
+ {
+ var rect_item = temp[kk];
+ double factor = scale_factor / temp[kk].Scale;
+
+ temp[kk].Height = temp[kk].Height * factor;
+ temp[kk].Width = temp[kk].Width * factor;
+ temp[kk].X = temp[kk].X * factor;
+ temp[kk].Y = temp[kk].Y * factor;
+
+ temp[kk].Scale = scale_factor;
+ }
+ m_textptrs[pagenum] = temp;
+ }
/* Only visible pages */
private void LinksOff()
@@ -2179,7 +2313,6 @@ namespace gsview
if (temp != null)
{
m_docPages[kk].LinkBox = null;
- m_docPages[kk].PageRefresh();
}
}
}
@@ -2191,11 +2324,13 @@ namespace gsview
for (int kk = m_currpage - range; kk <= m_currpage + range; kk++)
{
- var temp = m_docPages[kk].LinkBox;
- if (temp == null)
+ if (!(kk < 0 || kk > m_num_pages - 1))
{
- m_docPages[kk].LinkBox = m_page_link_list[kk];
- m_docPages[kk].PageRefresh();
+ var temp = m_docPages[kk].LinkBox;
+ if (temp == null)
+ {
+ m_docPages[kk].LinkBox = m_page_link_list[kk];
+ }
}
}
}
@@ -2237,15 +2372,1037 @@ namespace gsview
if (link.Type == Link_t.LINK_GOTO)
{
- if (m_currpage != link.PageNum && link.PageNum >= 0 &&
+ if (m_currpage != link.PageNum && link.PageNum >= 0 &&
link.PageNum < m_num_pages)
- RenderRange(link.PageNum, true);
+ RenderRange(link.PageNum, true);
}
else if (link.Type == Link_t.LINK_URI)
System.Diagnostics.Process.Start(link.Urilink.AbsoluteUri);
}
}
-#endregion Link
+ #endregion Link
+
+ #region TextSelection
+
+ /* Change cursor if we are over text block */
+ private void ExitTextBlock(object sender, System.Windows.Input.MouseEventArgs e)
+ {
+ this.Cursor = System.Windows.Input.Cursors.Arrow;
+ }
+
+ private void EnterTextBlock(object sender, System.Windows.Input.MouseEventArgs e)
+ {
+ this.Cursor = System.Windows.Input.Cursors.IBeam;
+ }
+
+ private void ClearSelections()
+ {
+ for (int kk = 0; kk < m_textSelect.Count; kk++)
+ {
+ m_lineptrs[m_textSelect[kk].pagenum].Clear();
+ if (m_docPages[m_textSelect[kk].pagenum].SelectedLines != null)
+ m_docPages[m_textSelect[kk].pagenum].SelectedLines.Clear();
+ }
+ m_textSelect.Clear();
+ m_textselected = false;
+ }
+
+ private void InitTextSelection(DocPage page)
+ {
+ if (m_textSelect != null)
+ ClearSelections();
+ else
+ m_textSelect = new List<textSelectInfo_t>();
+
+ m_intxtselect = true;
+
+ textSelectInfo_t selinfo = new textSelectInfo_t();
+ selinfo.pagenum = page.PageNum;
+ selinfo.first_line_full = false;
+ selinfo.last_line_full = false;
+ m_textSelect.Add(selinfo);
+ }
+
+ private void PageMouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (this.Cursor != System.Windows.Input.Cursors.IBeam)
+ return;
+
+ var page = ((FrameworkElement)e.Source).DataContext as DocPage;
+ Canvas can = ((FrameworkElement)e.Source).Parent as Canvas;
+ if (page == null || can == null)
+ return;
+
+ InitTextSelection(page);
+ var posit = e.GetPosition(can);
+
+ page.SelX = posit.X;
+ page.SelY = posit.Y;
+ page.SelAnchorX = posit.X;
+ page.SelAnchorY = posit.Y;
+ page.SelColor = m_regionselect;
+
+ /* Create new holder for lines highlighted */
+ m_lineptrs[page.PageNum] = new LinesText();
+ }
+
+ private void PageMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
+ {
+ if (e.LeftButton == MouseButtonState.Released || m_intxtselect == false)
+ return;
+
+ var page = ((FrameworkElement)e.Source).DataContext as DocPage;
+ Canvas can = ((FrameworkElement)e.Source).Parent as Canvas;
+ if (page == null || can == null)
+ return;
+ if (page.PageNum < 0)
+ return;
+ /* Store the location of our most recent page in case we exit window */
+ var pos = e.GetPosition(can);
+ m_lastY = pos.Y;
+ m_maxY = can.Height;
+ /* Don't allow the listview to maintain control of the mouse, we need
+ * to detect if we leave the window */
+ /* Make sure page is rendered */
+ if (page.Content != Page_Content_t.FULL_RESOLUTION ||
+ page.Zoom != m_doczoom)
+ {
+ RenderRange(page.PageNum, false);
+ }
+
+ UpdateSelection(pos, page);
+ }
+
+ /* Resize selection rect */
+ private void UpdateSelection(System.Windows.Point pos, DocPage page)
+ {
+ bool new_page = true;
+ TextLine start_line, end_line;
+ double x = 0, y, w = 0, h;
+ bool found_first = false;
+ bool above_anchor = true;
+ bool first_line_full = false;
+ bool last_line_full = false;
+
+ for (int kk = 0; kk < m_textSelect.Count; kk++)
+ if (m_textSelect[kk].pagenum == page.PageNum)
+ new_page = false;
+
+ /* See if we have gone back to a previous page */
+ if (!new_page && page.PageNum != m_textSelect[m_textSelect.Count - 1].pagenum)
+ {
+ DocPage curr_page = m_docPages[m_textSelect[m_textSelect.Count - 1].pagenum];
+ curr_page.SelHeight = 0;
+ curr_page.SelWidth = 0;
+ m_textSelect.RemoveAt(m_textSelect.Count - 1);
+ m_lineptrs[curr_page.PageNum].Clear();
+ curr_page.SelectedLines.Clear();
+ }
+ if (new_page)
+ {
+ /* New page */
+ page.SelX = pos.X;
+ page.SelY = pos.Y;
+ page.SelAnchorX = m_docPages[m_textSelect[m_textSelect.Count - 1].pagenum].SelAnchorX;
+ if (m_textSelect[m_textSelect.Count - 1].pagenum > page.PageNum)
+ {
+ page.SelAnchorY = page.Height;
+ }
+ else
+ {
+ page.SelAnchorY = 0;
+ }
+ page.SelColor = m_regionselect;
+ textSelectInfo_t info = new textSelectInfo_t();
+ info.pagenum = page.PageNum;
+ info.first_line_full = false;
+ info.last_line_full = false;
+ m_textSelect.Add(info);
+ /* Create new holder for lines highlighted */
+ m_lineptrs[page.PageNum] = new LinesText();
+ }
+
+ if (page.TextBlocks == null || page.TextBlocks.Count == 0)
+ return;
+
+ /* Width changes translate across the pages */
+ for (int jj = 0; jj < m_textSelect.Count; jj++)
+ {
+ DocPage curr_page = m_docPages[m_textSelect[jj].pagenum];
+ x = Math.Min(pos.X, curr_page.SelAnchorX);
+ w = Math.Max(pos.X, curr_page.SelAnchorX) - x;
+ curr_page.SelX = x;
+ curr_page.SelWidth = w;
+ }
+ /* Height is just the current page */
+ y = Math.Min(pos.Y, page.SelAnchorY);
+ h = Math.Max(pos.Y, page.SelAnchorY) - y;
+
+ /* Determine if we are going up or down */
+ if (pos.Y > page.SelAnchorY)
+ above_anchor = false;
+ page.SelY = y;
+ page.SelHeight = h;
+
+ /* Clear out what we currently have */
+ m_lineptrs[page.PageNum].Clear();
+
+ /* Stuff already selected above us */
+ if (m_textSelect.Count > 1)
+ found_first = true;
+ /* Moving backwards through pages */
+ if (m_textSelect.Count > 1 && m_textSelect[m_textSelect.Count - 2].pagenum > page.PageNum)
+ found_first = false;
+
+ for (int jj = 0; jj < page.TextBlocks.Count; jj++)
+ {
+ /* Text blocks are already scaled. Lines are not */
+ var intersect_blk = page.TextBlocks[jj].CheckIntersection(x, y, w, h);
+ var lines = page.TextBlocks[jj].TextLines;
+
+ if (intersect_blk == Intersection_t.FULL)
+ {
+ /* Just add all the lines for this block */
+ for (int kk = 0; kk < lines.Count; kk++)
+ m_lineptrs[page.PageNum].Add(lines[kk]);
+ if (jj == 0)
+ {
+ first_line_full = true;
+ found_first = true;
+ }
+ if (jj == page.TextBlocks.Count - 1)
+ last_line_full = true;
+ }
+ else if (intersect_blk != Intersection_t.NONE)
+ {
+ /* Now go through the lines */
+ for (int kk = 0; kk < lines.Count; kk++)
+ {
+ double scale = m_doczoom / lines[kk].Scale;
+ var intersect_line = lines[kk].CheckIntersection(x * scale, y * scale, w * scale, h * scale);
+ if (intersect_line == Intersection_t.FULL)
+ {
+ m_lineptrs[page.PageNum].Add(lines[kk]);
+ found_first = true;
+ if (jj == 0 && kk == 0)
+ first_line_full = true;
+ if (jj == page.TextBlocks.Count - 1 &&
+ kk == lines.Count - 1)
+ last_line_full = true;
+
+ }
+ else if (intersect_line == Intersection_t.PARTIAL)
+ {
+ double val;
+ var lett = lines[kk].TextCharacters;
+
+ /* Now go through the width. */
+ if (found_first)
+ {
+ if (above_anchor)
+ val = page.SelAnchorX;
+ else
+ val = pos.X;
+
+ /* our second partial line */
+ if (val > lines[kk].X * scale + lines[kk].Width * scale)
+ m_lineptrs[page.PageNum].Add(lines[kk]);
+ else
+ {
+ /* Use either anchor point or mouse pos */
+ end_line = new TextLine();
+ end_line.TextCharacters = new List<TextCharacter>();
+ end_line.Height = 0;
+ end_line.Scale = m_doczoom;
+ for (int mm = 0; mm < lett.Count; mm++)
+ {
+ double letscale = m_doczoom / lett[mm].Scale;
+ if (lett[mm].X * letscale < val)
+ {
+ /* Can set to special color for debug */
+ end_line.Color = m_textselectcolor;
+ /* special color for debug */
+ //end_line.Color = "#4000FF00";
+ end_line.Height = lines[kk].Height * scale;
+ end_line.Width = lett[mm].X * letscale + lett[mm].Width * letscale - lines[kk].X * scale;
+ end_line.Y = lines[kk].Y * scale;
+ end_line.X = lines[kk].X * scale;
+ end_line.TextCharacters.Add(lett[mm]);
+ }
+ else
+ break;
+ }
+ if (end_line.Height != 0)
+ m_lineptrs[page.PageNum].Add(end_line);
+ }
+ }
+ else
+ {
+ if (!above_anchor)
+ val = page.SelAnchorX;
+ else
+ val = pos.X;
+
+ /* our first partial line */
+ found_first = true;
+ if (val < lines[kk].X * scale)
+ m_lineptrs[page.PageNum].Add(lines[kk]);
+ else
+ {
+ start_line = new TextLine();
+ start_line.TextCharacters = new List<TextCharacter>();
+ start_line.Height = 0;
+ start_line.Scale = m_doczoom;
+ /* Use either anchor point or mouse pos */
+ for (int mm = 0; mm < lett.Count; mm++)
+ {
+ double letscale = m_doczoom / lett[mm].Scale;
+ if (lett[mm].X * letscale + lett[mm].Width * letscale >= val)
+ {
+ start_line.Color = m_textselectcolor;
+ /* special color for debug */
+ //start_line.Color = "#40FF0000";
+ start_line.Height = lines[kk].Height * scale;
+ start_line.Width = lines[kk].X * scale + lines[kk].Width * scale - lett[mm].X * letscale;
+ start_line.X = lett[mm].X * letscale;
+ start_line.Y = lines[kk].Y * scale;
+ start_line.TextCharacters.Add(lett[mm]);
+ break;
+ }
+ }
+ if (start_line.Height > 0)
+ m_lineptrs[page.PageNum].Add(start_line);
+ }
+ }
+ }
+ }
+ }
+ }
+ var txtsel = m_textSelect[m_textSelect.Count - 1];
+ txtsel.first_line_full = first_line_full;
+ txtsel.last_line_full = last_line_full;
+ m_textSelect[m_textSelect.Count - 1] = txtsel;
+
+ /* Adjust for scale before assigning */
+ var temp = m_lineptrs[page.PageNum];
+ for (int kk = 0; kk < temp.Count; kk++)
+ {
+ var rect_item = temp[kk];
+ double factor = m_doczoom / rect_item.Scale;
+
+ temp[kk].Height = temp[kk].Height * factor;
+ temp[kk].Width = temp[kk].Width * factor;
+ temp[kk].X = temp[kk].X * factor;
+ temp[kk].Y = temp[kk].Y * factor;
+
+ temp[kk].Scale = m_doczoom;
+ }
+ page.SelectedLines = m_lineptrs[page.PageNum];
+ }
+
+ /* A fix for handling column cases TODO FIXME */
+ private void UpdateSelectionCol(System.Windows.Point pos, DocPage page)
+ {
+ bool new_page = true;
+ TextLine start_line, end_line;
+ double x = 0, y, w = 0, h;
+ bool found_first = false;
+ bool above_anchor = true;
+ bool first_line_full = false;
+ bool last_line_full = false;
+
+ for (int kk = 0; kk < m_textSelect.Count; kk++)
+ if (m_textSelect[kk].pagenum == page.PageNum)
+ new_page = false;
+
+ /* See if we have gone back to a previous page */
+ if (!new_page && page.PageNum != m_textSelect[m_textSelect.Count - 1].pagenum)
+ {
+ DocPage curr_page = m_docPages[m_textSelect[m_textSelect.Count - 1].pagenum];
+ curr_page.SelHeight = 0;
+ curr_page.SelWidth = 0;
+ m_textSelect.RemoveAt(m_textSelect.Count - 1);
+ m_lineptrs[curr_page.PageNum].Clear();
+ curr_page.SelectedLines.Clear();
+ }
+ if (new_page)
+ {
+ /* New page */
+ page.SelX = pos.X;
+ page.SelY = pos.Y;
+ page.SelAnchorX = m_docPages[m_textSelect[m_textSelect.Count - 1].pagenum].SelAnchorX;
+ if (m_textSelect[m_textSelect.Count - 1].pagenum > page.PageNum)
+ {
+ page.SelAnchorY = page.Height;
+ }
+ else
+ {
+ page.SelAnchorY = 0;
+ }
+ page.SelColor = m_regionselect;
+ textSelectInfo_t info = new textSelectInfo_t();
+ info.pagenum = page.PageNum;
+ info.first_line_full = false;
+ info.last_line_full = false;
+ m_textSelect.Add(info);
+ /* Create new holder for lines highlighted */
+ m_lineptrs[page.PageNum] = new LinesText();
+ }
+
+ if (page.TextBlocks == null || page.TextBlocks.Count == 0)
+ return;
+
+ /* Width changes translate across the pages */
+ for (int jj = 0; jj < m_textSelect.Count; jj++)
+ {
+ DocPage curr_page = m_docPages[m_textSelect[jj].pagenum];
+ x = Math.Min(pos.X, curr_page.SelAnchorX);
+ w = Math.Max(pos.X, curr_page.SelAnchorX) - x;
+ curr_page.SelX = x;
+ curr_page.SelWidth = w;
+ }
+ /* Height is just the current page */
+ y = Math.Min(pos.Y, page.SelAnchorY);
+ h = Math.Max(pos.Y, page.SelAnchorY) - y;
+
+ /* Determine if we are going up or down */
+ if (pos.Y > page.SelAnchorY)
+ above_anchor = false;
+ page.SelY = y;
+ page.SelHeight = h;
+
+ /* Clear out what we currently have */
+ m_lineptrs[page.PageNum].Clear();
+
+ /* Stuff already selected above us */
+ if (m_textSelect.Count > 1)
+ found_first = true;
+ /* Moving backwards through pages */
+ if (m_textSelect.Count > 1 && m_textSelect[m_textSelect.Count - 2].pagenum > page.PageNum)
+ found_first = false;
+
+ /* To properly handle the multiple columns we have to find the last
+ * line and make sure that all blocks between our first and last
+ * line are included. To do this we do an initial step through the
+ * blocks looking at our intersections */
+ int first_block = -1;
+ int last_block = -1;
+ for (int jj = 0; jj < page.TextBlocks.Count; jj++ )
+ {
+ var intersect_blk = page.TextBlocks[jj].CheckIntersection(x, y, w, h);
+ if (intersect_blk == Intersection_t.NONE && first_block != -1)
+ {
+ last_block = jj; /* NB: this is just past last block */
+ break;
+ }
+ else if (intersect_blk != Intersection_t.NONE && first_block == -1)
+ first_block = jj; /* NB: this is the first block */
+ }
+ if (first_block == -1)
+ return;
+ if (last_block == -1)
+ {
+ /* Only 1 block */
+ last_block = first_block + 1;
+ }
+
+ for (int jj = first_block; jj < last_block; jj++)
+ {
+ /* Text blocks are already scaled. Lines are not */
+ var intersect_blk = page.TextBlocks[jj].CheckIntersection(x, y, w, h);
+ var lines = page.TextBlocks[jj].TextLines;
+
+ if (jj == first_block || jj == last_block - 1)
+ {
+ /* Partial cases */
+ if (intersect_blk == Intersection_t.FULL)
+ {
+ for (int kk = 0; kk < lines.Count; kk++)
+ m_lineptrs[page.PageNum].Add(lines[kk]);
+ if (jj == first_block)
+ {
+ first_line_full = true;
+ found_first = true;
+ }
+ if (jj == last_block - 1)
+ {
+ last_line_full = true;
+ }
+ }
+ else if (intersect_blk == Intersection_t.PARTIAL)
+ {
+ for (int kk = 0; kk < lines.Count; kk++)
+ {
+ double scale = m_doczoom / lines[kk].Scale;
+ var intersect_line = lines[kk].CheckIntersection(x * scale, y * scale, w * scale, h * scale);
+ if (intersect_line == Intersection_t.FULL)
+ {
+ m_lineptrs[page.PageNum].Add(lines[kk]);
+ found_first = true;
+ if (jj == 0 && kk == 0)
+ first_line_full = true;
+ if (jj == page.TextBlocks.Count - 1 &&
+ kk == lines.Count - 1)
+ last_line_full = true;
+
+ }
+ else if (intersect_line == Intersection_t.PARTIAL)
+ {
+ double val;
+ var lett = lines[kk].TextCharacters;
+
+ /* Now go through the width. */
+ if (found_first)
+ {
+ if (above_anchor)
+ val = page.SelAnchorX;
+ else
+ val = pos.X;
+
+ /* our second partial line */
+ if (val > lines[kk].X * scale + lines[kk].Width * scale)
+ m_lineptrs[page.PageNum].Add(lines[kk]);
+ else
+ {
+ /* Use either anchor point or mouse pos */
+ end_line = new TextLine();
+ end_line.TextCharacters = new List<TextCharacter>();
+ end_line.Height = 0;
+ end_line.Scale = m_doczoom;
+ for (int mm = 0; mm < lett.Count; mm++)
+ {
+ double letscale = m_doczoom / lett[mm].Scale;
+ if (lett[mm].X * letscale < val)
+ {
+ /* Can set to special color for debug */
+ end_line.Color = m_textselectcolor;
+ /* special color for debug */
+ //end_line.Color = "#4000FF00";
+ end_line.Height = lines[kk].Height * scale;
+ end_line.Width = lett[mm].X * letscale + lett[mm].Width * letscale - lines[kk].X * scale;
+ end_line.Y = lines[kk].Y * scale;
+ end_line.X = lines[kk].X * scale;
+ end_line.TextCharacters.Add(lett[mm]);
+ }
+ else
+ break;
+ }
+ if (end_line.Height != 0)
+ m_lineptrs[page.PageNum].Add(end_line);
+ }
+ }
+ else
+ {
+ if (!above_anchor)
+ val = page.SelAnchorX;
+ else
+ val = pos.X;
+
+ /* our first partial line */
+ found_first = true;
+ if (val < lines[kk].X * scale)
+ m_lineptrs[page.PageNum].Add(lines[kk]);
+ else
+ {
+ start_line = new TextLine();
+ start_line.TextCharacters = new List<TextCharacter>();
+ start_line.Height = 0;
+ start_line.Scale = m_doczoom;
+ /* Use either anchor point or mouse pos */
+ for (int mm = 0; mm < lett.Count; mm++)
+ {
+ double letscale = m_doczoom / lett[mm].Scale;
+ if (lett[mm].X * letscale + lett[mm].Width * letscale >= val)
+ {
+ start_line.Color = m_textselectcolor;
+ /* special color for debug */
+ //start_line.Color = "#40FF0000";
+ start_line.Height = lines[kk].Height * scale;
+ start_line.Width = lines[kk].X * scale + lines[kk].Width * scale - lett[mm].X * letscale;
+ start_line.X = lett[mm].X * letscale;
+ start_line.Y = lines[kk].Y * scale;
+ start_line.TextCharacters.Add(lett[mm]);
+ break;
+ }
+ }
+ if (start_line.Height > 0)
+ m_lineptrs[page.PageNum].Add(start_line);
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Add all the lines for the blocks between the first and last */
+ for (int kk = 0; kk < lines.Count; kk++)
+ m_lineptrs[page.PageNum].Add(lines[kk]);
+ }
+ }
+
+ var txtsel = m_textSelect[m_textSelect.Count - 1];
+ txtsel.first_line_full = first_line_full;
+ txtsel.last_line_full = last_line_full;
+ m_textSelect[m_textSelect.Count - 1] = txtsel;
+
+ /* Adjust for scale before assigning */
+ var temp = m_lineptrs[page.PageNum];
+ for (int kk = 0; kk < temp.Count; kk++)
+ {
+ var rect_item = temp[kk];
+ double factor = m_doczoom / rect_item.Scale;
+
+ temp[kk].Height = temp[kk].Height * factor;
+ temp[kk].Width = temp[kk].Width * factor;
+ temp[kk].X = temp[kk].X * factor;
+ temp[kk].Y = temp[kk].Y * factor;
+
+ temp[kk].Scale = m_doczoom;
+ }
+ page.SelectedLines = m_lineptrs[page.PageNum];
+ }
+
+ private void CheckIfSelected()
+ {
+ m_textselected = false;
+ /* Check if anything was selected */
+ for (int kk = 0; kk < m_lineptrs.Count; kk++)
+ {
+ if (m_lineptrs[kk].Count > 0)
+ {
+ m_textselected = true;
+ break;
+ }
+ }
+ }
+
+ /* Rect should be removed */
+ private void PageLeftClickUp(object sender, MouseButtonEventArgs e)
+ {
+ m_intxtselect = false;
+ CheckIfSelected();
+ }
+
+ private void StepScroll(int stepsize)
+ {
+ ScrollViewer viewer = FindScrollViewer(xaml_PageList);
+ if (viewer != null)
+ {
+ var scrollpos = viewer.VerticalOffset;
+ viewer.ScrollToVerticalOffset(scrollpos + stepsize);
+ }
+ }
+
+ /* Recursive call to find the scroll viewer */
+ private ScrollViewer FindScrollViewer(DependencyObject d)
+ {
+ if (d is ScrollViewer)
+ return d as ScrollViewer;
+
+ for (int i = 0; i < VisualTreeHelper.GetChildrenCount(d); i++)
+ {
+ var sw = FindScrollViewer(VisualTreeHelper.GetChild(d, i));
+ if (sw != null) return sw;
+ }
+ return null;
+ }
+
+ /* Only worry about cases where we are moving and left button is down */
+ private void ListPreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
+ {
+ var relPoint = e.GetPosition(xaml_PageList);
+ var absPoint = this.PointToScreen(relPoint);
+ Console.Write("abs Y position = " + absPoint.Y + "\n");
+ Console.Write("rel Y position = " + relPoint.Y + "\n");
+ Console.Write("Height is = " + (this.Top + this.Height) + "\n");
+
+ if (xaml_PageList.IsMouseCaptured == true)
+ {
+ if (!m_intxtselect)
+ {
+ xaml_PageList.ReleaseMouseCapture();
+ e.Handled = true;
+ return;
+ }
+
+ if (relPoint.Y < Constants.SCROLL_EDGE_BUFFER ||
+ absPoint.Y > (this.Top + this.Height - Constants.SCROLL_EDGE_BUFFER))
+ {
+ if (m_dispatcherTimer == null)
+ {
+ m_dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
+ m_dispatcherTimer.Tick += new EventHandler(dispatcherTimerTick);
+ m_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, Constants.DISPATCH_TIME);
+ }
+ if (m_dispatcherTimer.IsEnabled == false)
+ m_dispatcherTimer.Start();
+ e.Handled = true;
+ }
+
+ /* This is not desirable, but the scrollviewer behaves badly
+ * when it has captured the mouse and we move beyond the
+ * range. So we wont allow it */
+ if (relPoint.Y < 0 ||
+ absPoint.Y > (this.Top + this.Height) - Constants.SCROLL_EDGE_BUFFER / 2.0)
+ {
+ xaml_PageList.ReleaseMouseCapture();
+ e.Handled = true;
+ if (m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled == true)
+ m_dispatcherTimer.Stop();
+ return;
+ }
+ }
+ }
+
+ private void ListPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ if (m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled)
+ {
+ m_dispatcherTimer.Stop();
+ }
+ }
+
+ private void ListMouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
+ {
+ if (m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled)
+ {
+ m_dispatcherTimer.Stop();
+ }
+ if (xaml_PageList.IsMouseCaptured == true)
+ xaml_PageList.ReleaseMouseCapture();
+ }
+
+ /* Get mouse position, update selection accordingly */
+ private void dispatcherTimerTick(object sender, EventArgs e)
+ {
+ var position = this.PointToScreen(Mouse.GetPosition(xaml_PageList));
+ Console.Write("Y position = " + position.Y + "\n");
+ Console.Write("Top position = " + this.Top + "\n");
+ Console.Write("Bottom position = " + (this.Top + this.Height) + "\n");
+
+ DocPage page;
+ int page_num;
+
+ if (!xaml_PageList.IsMouseCaptured)
+ {
+ Console.Write("Lost capture\n");
+ return;
+ }
+ else
+ {
+ Console.Write("Have capture\n");
+ }
+ /* Get our most recent page */
+ var pageinfo = m_textSelect[m_textSelect.Count - 1];
+ page_num = pageinfo.pagenum;
+
+ /* Scrolling up */
+ if (position.Y > this.Top + this.Height - Constants.SCROLL_EDGE_BUFFER)
+ {
+ /* See if we have the last line for this page */
+ if (pageinfo.last_line_full)
+ {
+ page_num = page_num + 1;
+ m_lastY = 0;
+ if (page_num >= m_num_pages)
+ return;
+ }
+ page = m_docPages[page_num];
+ StepScroll(Constants.SCROLL_STEP);
+ /* Set position for proper selection update */
+ m_lastY = m_lastY + Constants.SCROLL_STEP;
+ if (m_lastY > m_maxY)
+ m_lastY = m_maxY;
+ position.Y = m_lastY;
+ UpdateSelection(position, page);
+ }
+ else if (position.Y < this.Top + Constants.SCROLL_EDGE_BUFFER)
+ {
+ /* See if we have the first line for this page */
+ if (pageinfo.first_line_full)
+ {
+ if (page_num <= 0)
+ return;
+ page_num = page_num - 1;
+ m_lastY = m_docPages[page_num].Height;
+ }
+ page = m_docPages[page_num];
+ StepScroll(-Constants.SCROLL_STEP);
+ /* Set position for proper selection update */
+ m_lastY = m_lastY - Constants.SCROLL_STEP;
+ if (m_lastY < 0)
+ m_lastY = 0;
+ position.Y = m_lastY;
+ UpdateSelection(position, page);
+ }
+ }
+
+ private void ListPreviewLeftButtonUp(object sender, MouseButtonEventArgs e)
+ {
+ if (m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled)
+ {
+ m_dispatcherTimer.Stop();
+ }
+ }
+
+ private void ShowContextMenu(object sender, MouseButtonEventArgs e)
+ {
+ if (this.Cursor != System.Windows.Input.Cursors.IBeam)
+ return;
+
+ var contextmenu = new System.Windows.Controls.ContextMenu();
+ Canvas can = ((FrameworkElement)e.Source).Parent as Canvas;
+ var page = ((FrameworkElement)e.Source).DataContext as DocPage;
+ if (can == null || page == null)
+ return;
+
+ var posit = e.GetPosition(can);
+ ContextMenu_t info = new ContextMenu_t();
+ info.mouse_position = posit;
+ info.page_num = page.PageNum;
+ can.ContextMenu = contextmenu;
+
+ if (m_textselected)
+ {
+ var m1 = new System.Windows.Controls.MenuItem();
+ m1.Header = "Copy";
+
+ /* amazing what I have to do here to get the icon out of the
+ * resources into something that wpf can use */
+ var iconres = Properties.Resources.copy;
+ var bitmap = iconres.ToBitmap();
+ using (MemoryStream memory = new MemoryStream())
+ {
+ bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
+ memory.Position = 0;
+ BitmapImage bitmapImage = new BitmapImage();
+ bitmapImage.BeginInit();
+ bitmapImage.StreamSource = memory;
+ bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
+ bitmapImage.EndInit();
+ Image iconImage = new Image();
+ iconImage.Source = bitmapImage;
+ m1.Icon = iconImage;
+ m1.Click += cntxMenuCopy;
+ contextmenu.Items.Add(m1);
+ }
+
+ var m6 = new System.Windows.Controls.MenuItem();
+ m6.Header = "Deselect All";
+ m6.Click += cntxMenuDeselectAll;
+ contextmenu.Items.Add(m6);
+
+ /* Below to be enabled when we add annotations */
+ /*
+ var ma1 = new System.Windows.Controls.MenuItem();
+ ma1.Header = "Highlight";
+ ma1.Click += cntxMenuHighlight;
+ contextmenu.Items.Add(ma1);
+
+ var ma2 = new System.Windows.Controls.MenuItem();
+ ma2.Header = "Underline";
+ ma2.Click += cntxMenuUnderline;
+ contextmenu.Items.Add(ma2);
+
+ var ma3 = new System.Windows.Controls.MenuItem();
+ ma3.Header = "Strikeout";
+ ma3.Click += cntxMenuStrike;
+ contextmenu.Items.Add(ma3);*/
+
+ }
+ var m2 = new System.Windows.Controls.MenuItem();
+ m2.Header = "Select Line";
+ m2.Click += cntxMenuSelectLine;
+ m2.Tag = info;
+ contextmenu.Items.Add(m2);
+
+ var m3 = new System.Windows.Controls.MenuItem();
+ m3.Header = "Select Block";
+ m3.Click += cntxMenuSelectBlock;
+ m3.Tag = info;
+ contextmenu.Items.Add(m3);
+
+ var m4 = new System.Windows.Controls.MenuItem();
+ m4.Header = "Select Page";
+ m4.Click += cntxMenuSelectPage;
+ m4.Tag = info;
+ contextmenu.Items.Add(m4);
+
+ var m5 = new System.Windows.Controls.MenuItem();
+ m5.Header = "Select All";
+ m5.Click += cntxMenuSelectAll;
+ contextmenu.Items.Add(m5);
+ }
+
+ private void cntxMenuCopy(object sender, RoutedEventArgs e)
+ {
+ /* Go through and get each line of text */
+ String result = null;
+
+ for (int kk = 0; kk < m_textSelect.Count; kk++)
+ {
+ var lines = m_lineptrs[m_textSelect[kk].pagenum];
+ for (int jj = 0; jj < lines.Count; jj++)
+ {
+ var text = lines[jj].TextCharacters;
+ for (int mm = 0; mm < text.Count; mm++)
+ {
+ result += text[mm].character;
+ }
+ result += "\r\n";
+ }
+ }
+ System.Windows.Clipboard.SetText(result);
+ }
+
+ private void cntxMenuSelectLine(object sender, RoutedEventArgs e)
+ {
+ var mi = sender as System.Windows.Controls.MenuItem;
+ ContextMenu_t info = (ContextMenu_t)mi.Tag;
+ var page = m_docPages[info.page_num];
+
+ InitTextSelection(page);
+
+ page.SelX = 0;
+ page.SelY = info.mouse_position.Y - 1;
+ page.SelAnchorX = 0;
+ page.SelAnchorY = info.mouse_position.Y - 1;
+ page.SelColor = m_regionselect;
+
+ /* Create new holder for lines highlighted */
+ m_lineptrs[page.PageNum] = new LinesText();
+
+ Point pos = new Point();
+ pos.X = page.Width;
+ pos.Y += info.mouse_position.Y + 1;
+
+ UpdateSelection(pos, page);
+ CheckIfSelected();
+ }
+
+ /* This one requires its own special handling TODO FIXME */
+ private void cntxMenuSelectBlock(object sender, RoutedEventArgs e)
+ {
+ var mi = sender as System.Windows.Controls.MenuItem;
+ ContextMenu_t info = (ContextMenu_t)mi.Tag;
+ var page = m_docPages[info.page_num];
+ bool found = false;
+ int jj;
+
+ InitTextSelection(page);
+
+ /* Find the block that we are in */
+ for (jj = 0; jj < page.TextBlocks.Count; jj++)
+ {
+ var intersect_blk = page.TextBlocks[jj].CheckIntersection(info.mouse_position.X, info.mouse_position.Y, 1, 1);
+ if (intersect_blk != Intersection_t.NONE)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ {
+ page.SelX = page.TextBlocks[jj].X;
+ page.SelY = page.TextBlocks[jj].Y;
+ page.SelAnchorX = page.TextBlocks[jj].X;
+ page.SelAnchorY = page.TextBlocks[jj].Y;
+ page.SelColor = m_regionselect;
+
+ /* Create new holder for lines highlighted */
+ m_lineptrs[page.PageNum] = new LinesText();
+
+ Point pos = new Point();
+ pos.X = page.TextBlocks[jj].X + page.TextBlocks[jj].Width;
+ pos.Y = page.TextBlocks[jj].Y + page.TextBlocks[jj].Height;
+
+ UpdateSelection(pos, page);
+ CheckIfSelected();
+ }
+ else
+ m_textselected = false;
+ }
+
+ private void SelectFullPage(int page_num)
+ {
+ var page = m_docPages[page_num];
+
+ InitTextSelection(page);
+
+ page.SelX = 0;
+ page.SelY = 0;
+ page.SelAnchorX = 0;
+ page.SelAnchorY = 0;
+ page.SelColor = m_regionselect;
+
+ /* Create new holder for lines highlighted */
+ m_lineptrs[page.PageNum] = new LinesText();
+
+ Point pos = new Point();
+ pos.X = page.Width;
+ pos.Y = page.Height;
+
+ UpdateSelection(pos, page);
+ }
+
+ private void cntxMenuSelectPage(object sender, RoutedEventArgs e)
+ {
+ var mi = sender as System.Windows.Controls.MenuItem;
+ ContextMenu_t info = (ContextMenu_t)mi.Tag;
+
+ SelectFullPage(info.page_num);
+ CheckIfSelected();
+ }
+
+ /* We need to await on the render range TODO FIXME */
+ private void cntxMenuSelectAll(object sender, RoutedEventArgs e)
+ {
+ var mi = sender as System.Windows.Controls.MenuItem;
+ if (m_textSelect != null)
+ ClearSelections();
+ else
+ m_textSelect = new List<textSelectInfo_t>();
+
+ /* Do first one and then the rest occur as new pages */
+ /* Note that we have to render the pages TODO FIXME */
+ SelectFullPage(0);
+ for (int kk = 1; kk < m_num_pages; kk++)
+ {
+ if (!m_textset[kk])
+ RenderRange(kk, false);
+ var page = m_docPages[kk];
+ Point pos = new Point();
+ pos.X = page.Width;
+ pos.Y = page.Height;
+ UpdateSelection(pos, page);
+ }
+ CheckIfSelected();
+ }
+
+ private void cntxMenuDeselectAll(object sender, RoutedEventArgs e)
+ {
+ ClearSelections();
+ }
+
+ /* To add with annotation support */
+ /*
+ private void cntxMenuHighlight(object sender, RoutedEventArgs e)
+ {
+
+ }
+
+ private void cntxMenuUnderline(object sender, RoutedEventArgs e)
+ {
+
+ }
+
+ private void cntxMenuStrike(object sender, RoutedEventArgs e)
+ {
+
+ }
+ */
+ #endregion TextSelection
}
} \ No newline at end of file