Okay, I have it working the way I want. I'm posting my changes here in case it helps someone else, or in case you'd want to integrate this into the product. Rather than modifying dev_view=6, I created a new def_view=100 to avoid conflicts with future versions.
Class: PDFLayoutView
Method: PDFSetView
Line in method: 38
Add this case statement:
case 100: {
// arlo added: don't let the first page appear alone in either orientation
PDFLayoutDual layout = new PDFLayoutDual(getContext());
boolean paras[] = new boolean[m_doc.GetPageCount()];
int cur = 0;
while (cur < paras.length) {
paras[cur] = true;
cur++;
}
layout.vSetLayoutPara(paras, paras, Global.rtol, false);
m_layout = layout;
}
Class: PDFViewDual
Method: vOnFling
Line in method: 8
Change "Global.def_view == 6" to "(Global.def_view == 6 || Global.def_view == 100)"
Class: PDFLayoutDual
Method: (class definition)
Line in method: 9
Add these two lines to the forward class declaration for PDFCell:
public int top;
public int bottom;
Class: PDFLayoutDual
Method: vLayout
Line in method: 11
Replace "if( m_h > m_w )" with "if ((Global.def_view != 100)&&( m_h > m_w ))" because I want to always use two columns, even with a portrait-oriented viewer.
Then go to the "else" section of that condition and replace the entire block with:
while( pcur < pcnt )
{
// arlo comment: this section gets the width and height of each pair of pages
if( (m_horz_dual == null || ccnt >= m_horz_dual.length/* || m_horz_dual[ccnt]*/) && pcur == 0 )
{
// arlo comment: first page if it appears alone; we're avoiding this by setting horzs in vSetLayoutPara
float w = m_doc.GetPageWidth(pcur);
if( max_w < w ) max_w = w;
float h = m_doc.GetPageHeight(pcur);
if( max_h < h ) max_h = h;
if(Global.fit_different_page_size && m_scales[pcur] == 0) {
m_scales[pcur] = ((float)(m_h - m_page_gap)) / h;
m_scales_min[pcur] = ((float)(m_h - m_page_gap)) / h;
}
pcur++;
}
else
if( (m_horz_dual == null || ccnt >= m_horz_dual.length || m_horz_dual[ccnt]) && pcur < pcnt - 1 )
{
// arlo comment: pairs of pages
float w = m_doc.GetPageWidth(pcur) + m_doc.GetPageWidth(pcur + 1);
if( max_w < w ) max_w = w;
float h = m_doc.GetPageHeight(pcur);
if( max_h < h ) max_h = h;
h = m_doc.GetPageHeight(pcur + 1);
if( max_h < h ) max_h = h;
if(Global.fit_different_page_size && m_scales[pcur] == 0) {
float minScale = (m_w - m_page_gap) / w;
float scale = ((float)(m_h - m_page_gap)) / m_doc.GetPageHeight(pcur);
if( minScale > scale ) minScale = scale;
m_scales[pcur] = minScale;
m_scales_min[pcur] = minScale;
scale = ((float)(m_h - m_page_gap)) / m_doc.GetPageHeight(pcur + 1);
if( minScale > scale ) minScale = scale;
m_scales[pcur + 1] = minScale;
m_scales_min[pcur + 1] = minScale;
}
pcur += 2;
}
else
{
// arlo comment: last page if it appears alone
float w = m_doc.GetPageWidth(pcur);
if( max_w < w ) max_w = w;
float h = m_doc.GetPageHeight(pcur);
if( max_h < h ) max_h = h;
if(Global.fit_different_page_size && m_scales[pcur] == 0) {
m_scales[pcur] = ((float)(m_h - m_page_gap)) / h;
m_scales_min[pcur] = ((float)(m_h - m_page_gap)) / h;
}
pcur++;
}
ccnt++;
}
m_scale_min = ((float) (m_w - m_page_gap)) / max_w;
if (Global.def_view != 100) {
// arlo removed: don't fit to height because I'm handling that outside the viewer; other people will probably want to leave this as it was
float scale = ((float)(m_h - m_page_gap)) / max_h;
if( m_scale_min > scale ) m_scale_min = scale;
}
m_scale_max = m_scale_min * m_zoom_level;
if( m_scale < m_scale_min ) m_scale = m_scale_min;
if( m_scale > m_scale_max ) m_scale = m_scale_max;
boolean clip = m_scale / m_scale_min > m_zoom_level_clip;
if (Global.def_view == 100) {
// arlo added: set the total size of the static dimension
m_tw = Global.fit_different_page_size && vGetScale() == vGetMinScale() ? m_w : (int) (max_w * m_scale) + m_page_gap;
} else {
m_th = Global.fit_different_page_size && vGetScale() == vGetMinScale() ? m_h : (int) (max_h * m_scale) + m_page_gap;
}
if (m_th < m_h) m_th = m_h;
m_cells = new PDFCell[ccnt];
pcur = 0;
ccur = 0;
int left = 0;
int top = 0; // arlo added
while( ccur < ccnt )
{
PDFCell cell = new PDFCell();
int w = 0;
int h = 0;
int cw = 0;
int ch = 0;
boolean clipPage = Global.fit_different_page_size ? m_scales[pcur] / m_scales_min[pcur] > m_zoom_level_clip : clip;
float pageScale = Global.fit_different_page_size ? m_scales[pcur] : m_scale;
if ((m_horz_dual == null || ccur >= m_horz_dual.length ) && pcur == 0 )
{
// arlo comment: position the first page if it appears alone; we're avoiding this by setting horzs in vSetLayoutPara
w = (int)( m_doc.GetPageWidth(pcur) * pageScale );
h = (int)( m_doc.GetPageHeight(pcur) * pageScale );
if( w + m_page_gap < m_w ) cw = m_w;
else cw = w + m_page_gap;
if( h + m_page_gap < m_h ) ch = m_h;
else ch = h + m_page_gap;
cell.page_left = pcur;
cell.page_right = -1;
cell.left = left;
cell.right = left + cw;
cell.top = top; // arlo added
cell.bottom = top + ch; // arlo added
if(m_page_align_top)
{
m_pages[pcur].vLayout(left + (cw - w) / 2, m_page_gap / 2, pageScale, clipPage);
}
else {
if (Global.def_view == 100) {
// arlo added
m_pages[pcur].vLayout(left + (cw - w) / 2, top + (ch - h) / 2, pageScale, clipPage);
} else {
m_pages[pcur].vLayout(left + (cw - w) / 2, (int) (m_th - m_doc.GetPageHeight(pcur) * pageScale) / 2, pageScale, clipPage);
}
}
pcur++;
}
else if( (m_horz_dual == null || ccur >= m_horz_dual.length || m_horz_dual[ccur]) && pcur < pcnt - 1 )
{
// arlo comment: position pairs of pages
float pageScale2 = Global.fit_different_page_size ? m_scales[pcur + 1] : m_scale;
w = Global.fit_different_page_size ? (int)( (m_doc.GetPageWidth(pcur) * pageScale) + (m_doc.GetPageWidth(pcur + 1)
* pageScale2)) : (int)( (m_doc.GetPageWidth(pcur) + m_doc.GetPageWidth(pcur + 1)) * pageScale);
h = Global.fit_different_page_size ? (int)( Math.max((m_doc.GetPageHeight(pcur) * pageScale), (m_doc.GetPageHeight(pcur + 1)
* pageScale2)) ) : (int)( Math.max((m_doc.GetPageHeight(pcur) * pageScale), (m_doc.GetPageHeight(pcur + 1) * pageScale)) );
if( w + m_page_gap < m_w ) cw = m_w;
else cw = w + m_page_gap;
if( h + m_page_gap < m_h ) ch = m_h;
else ch = h + m_page_gap;
cell.page_left = pcur;
cell.page_right = pcur + 1;
cell.left = left + 10; // I have no idea why, but without the +10 here, only the middle cell appears
cell.right = left + cw - 10; // ditto
cell.top = top; // arlo added
cell.bottom = top + ch; // arlo added
if(m_page_align_top)
{
m_pages[pcur].vLayout(left + (cw - w) / 2, m_page_gap / 2, pageScale, clip);
m_pages[pcur + 1].vLayout(m_pages[pcur].GetX() + m_pages[pcur].GetWidth(), m_page_gap / 2, pageScale2, clip);
}
else {
if (Global.def_view == 100) {
// arlo added
m_pages[pcur].vLayout(left + (cw - w) / 2, top + (ch - h) / 2, pageScale, clip);
m_pages[pcur + 1].vLayout(m_pages[pcur].GetX() + m_pages[pcur].GetWidth(), top + (ch - h) / 2, pageScale2, clip);
} else {
m_pages[pcur].vLayout(left + (cw - w) / 2, (int) (m_th - m_doc.GetPageHeight(pcur) * pageScale) / 2, pageScale, clip);
m_pages[pcur + 1].vLayout(m_pages[pcur].GetX() + m_pages[pcur].GetWidth(), (int) (m_th - m_doc.GetPageHeight(pcur + 1) * pageScale2) / 2, pageScale2, clip);
}
}
pcur += 2;
}
else
{
// arlo comment: position the last page if it appears alone
w = (int)( m_doc.GetPageWidth(pcur) * pageScale );
h = (int)( m_doc.GetPageHeight(pcur) * pageScale );
if( w + m_page_gap < m_w ) cw = m_w;
else cw = w + m_page_gap;
if( h + m_page_gap < m_h ) ch = m_h;
else ch = h + m_page_gap;
cell.page_left = pcur;
cell.page_right = -1;
cell.left = left;
cell.right = left + cw;
cell.top = top; // arlo added
cell.bottom = top + ch; // arlo added
if(m_page_align_top)
{
m_pages[pcur].vLayout(left + (cw - w) / 2, m_page_gap / 2, pageScale, clipPage);
}
else {
if (Global.def_view == 100) {
// arlo added
m_pages[pcur].vLayout(left + (cw - w) / 2, top + (ch - h) / 2, pageScale, clipPage);
} else {
m_pages[pcur].vLayout(left + (cw - w) / 2, (int) (m_th - m_doc.GetPageHeight(pcur) * pageScale) / 2, pageScale, clipPage);
}
}
pcur++;
}
if (Global.def_view == 100) {
// arlo added
top += ch;
} else {
left += cw;
}
m_cells[ccur] = cell;
ccur++;
}
if (Global.def_view == 100) {
// arlo added: set the total size of the scrolling dimension
m_th = top;
} else {
m_tw = left;
}
Here's a screen recording showing how it works: