/* Nile1View.java * * Copyright (c) 2000, Ted Nelson and Tuomas Lukka * * You may use and distribute under the terms of either the GNU Lesser * General Public License, either version 2 of the license or, * at your choice, any later version. Alternatively, you may use and * distribute under the terms of the XPL. * * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of * the licenses. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README * file for more details. * */ /* * Written by Tuomas Lukka */ package org.gzigzag.module; import org.gzigzag.*; import java.util.*; import java.awt.*; import java.io.*; /** A view for nile streams. */ public class Nile1View implements FlobView, ZOb { public static final String rcsid = "$Id: Nile1View.zob,v 1.1 2002/10/07 12:37:34 tuukkah Exp $"; public static boolean dbg = false; static void p(String s) { if(dbg) System.out.println(s); } static void pa(String s) { System.out.println(s); } STRUCTPARAMS { /** The default font to use. */ Font font = new Font("SansSerif", Font.PLAIN, 11); /** The distance between paragraphs. */ int paraskip = 8; /** The left-side margin for normal text. * Headings hang left of this margin. */ int lmargin = 50; ZOb ftextlayouter = new FTextLayouter(); /** Whether to use a special color for span (transcluded) cells. */ boolean showcopy = false; } /** Bold and italic derivatives of the font given. * The first index is the level of the text i.e. * from paragraph to H1. */ Font[][][] bifonts; FontMetrics[][][] bifontms; INITIALIZE { bifonts = new Font[7][2][2]; bifontms = new FontMetrics[7][2][2]; for(int l = 0; l < bifonts.length; l++) { int size = font.getSize(); if(l > 0 && l < 5) size += l-1; if(l == 5) size += 6; if(l == 6) size += 9; bifonts[l][1][0] = new Font(font.getName(), Font.BOLD, size); bifonts[l][1][1] = new Font(font.getName(), Font.BOLD | Font.ITALIC, size); if(l == 0) { bifonts[l][0][0] = new Font(font.getName(), 0, size); bifonts[l][0][1] = new Font(font.getName(), Font.ITALIC, size); } else { // All bold for headers bifonts[l][0][0] = bifonts[l][1][0]; bifonts[l][0][1] = bifonts[l][1][1]; } for(int b = 0; b<2; b++) for(int i = 0; i<2; i++) bifontms[l][b][i] = FONTMETRICS(bifonts[l][b][i]); } } Color selcolor = Color.white; Color copycolor = Color.yellow.darker().darker().darker().darker(); /** Return the formatted text object for one paragraph. */ FText paragraph(ZZCell start, ZZCell endBefore, ZZCursor offsetOfC, int[]into, ZZCursor selectEnd) { p("Paragraph! "+start+" "+endBefore+" "); ZZCell selsc = null; int selso = 0; if(offsetOfC != null) { selsc = offsetOfC.get(); selso = offsetOfC.getOffs(); } ZZCell offsetOf = selsc; ZZCell selec = null; int seleo = 0; if(selectEnd != null) { selec = selectEnd.get(); seleo = selectEnd.getOffs(); } boolean selected = (selsc == null && selec != null); if(selso == ZZCursor.NO_OFFSET || selec == null) { selsc = null; selec = null; selected = false; } FText.Part part = null; int level = Nile2Iter.getLevel(start); int curOffs = 0; int b = 0, i = 0; Vector parts = new Vector(); LoopDetector ld = new LoopDetector(); LoopDetector ld2 = new LoopDetector(); for(ZZCell c = start; c != null && c != endBefore; c = c.s("d.nile")) { ld.detect(c); for(ZZCell fs = c.s("d.nile-fmt-start"); fs != null; fs = fs.s("d.nile-fmt-start")) { ld.detect(fs); if(fs.getText().equals("B")) b++; else if(fs.getText().equals("I")) i++; else p("Invalid format: "+fs.getText()); } int b0 = (b > 0 ? 1 : 0); int i0 = (i > 0 ? 1 : 0); int len = c.getText().length(); if(c == offsetOf && into != null) into[0] = curOffs; int internoffs = 0; if(c == selsc) { if(selso > len) { ZZLogger.log("Warning: start over length "+selso+" "+len); selso = len; } part = new FText.CellPart( c, 0, selso, bifonts[level][b0][i0], bifontms[level][b0][i0], null, c.getSpan() == null ? null : copycolor); parts.addElement(part); internoffs = selso; selected = true; p("Start selection: "+selso+" "+selsc); } if(c == selec && seleo >= internoffs) { if(seleo > len) { ZZLogger.log("Warning: end over length "+seleo+" "+len); seleo = len; } part = new FText.CellPart( c, internoffs, seleo-internoffs, bifonts[level][b0][i0], bifontms[level][b0][i0], selcolor, c.getSpan() == null ? null : copycolor); parts.addElement(part); internoffs = seleo; selected = false; selectEnd.set((ZZCell)null); p("End selection: "+seleo+" "+selec); } part = new FText.CellPart( c, internoffs, len-internoffs, bifonts[level][b0][i0], bifontms[level][b0][i0], selected ? selcolor : null, c.getSpan() == null ? null : copycolor); parts.addElement(part); curOffs += len; for(ZZCell fe = c.s("d.nile-fmt-end"); fe != null; fe = fe.s("d.nile-fmt-start")) { ld2.detect(fe); // Can't use same: same cell is start&end if(fe.getText().equals("B")) b--; else if(fe.getText().equals("I")) i--; else p("Invalid format: "+fe.getText()); } } return new FText(parts); } Rectangle pmarg(Rectangle r, ZZCell para) { int level = Nile2Iter.getLevel(para); Rectangle ret = new Rectangle(r); int w = (6 - level) * lmargin / 6; ret.x += w; ret.width -= w; return ret; } boolean[] beginningSentence = new boolean[2]; public Rectangle placeParagraph(FlobSet into, FText ft, ZZCell para,Rectangle origrect, int direction, int initY, int middleOffs) { beginningSentence[0] = true; beginningSentence[1] = false; // Margins. Rectangle rect = pmarg(origrect, para); Rectangle ret = ((FTextLayouter)ftextlayouter).place(into, ft, rect, 1, direction, initY, middleOffs, false, beginningSentence); // Now, do the cool thing with the section headings: include // previous and next section headings of the same level here. if(Nile2Iter.getLevel(para) > 0) { ZZCell strcell = para.s("d.nile-struct"); if(strcell == null) return ret; for(int dir = -1; dir <= 1; dir += 2) { ZZCell prevsec = strcell.s("nile1str:breadth",dir); if(prevsec == null) continue; prevsec = prevsec.h("nile1str:depth").s("d.nile-struct", -1); if(prevsec == null) continue; beginningSentence[0] = true; beginningSentence[1] = false; FText nft = paragraph(prevsec, Nile2Iter.findStruct(prevsec, 1, false), null, null, null); ((FTextLayouter)ftextlayouter).place(into, nft, rect, 200, dir, ret.y + (dir < 0 ? 0 : ret.height), 0, false, beginningSentence); } } return ret; } public void raster(FlobSet into, FlobFactory fact, ZZCell view, String[] dims, ZZCell accursed) { int[] offs = new int[1]; LoopDetector ld = new LoopDetector(); ZZCursor selectEnd = null; ZZCell sele = view.s("d.nile-sel"); if(sele != null) { selectEnd = ZZCursorVirtual.createFromReal(sele); } // Do the center paragraph first. ZZCell firstpara = Nile2Iter.findStruct(accursed, -1, true); ZZCell nextpara = Nile2Iter.findStruct(accursed, 1, false); FText ft = paragraph(firstpara, nextpara, new ZZCursorReal(view), offs, selectEnd); Dimension size = into.getSize(); Rectangle rect = new Rectangle(0, 0, size.width, size.height); Rectangle ctr = placeParagraph(into, ft, firstpara, rect, 0, rect.y+rect.height/2, ZZCursorReal.getVisualTextOffset(view)); // Go into positive direction. Rectangle r = ctr; while(nextpara != null) { ld.detect(nextpara); ZZCell next = Nile2Iter.findStruct(nextpara, 1, false); ft = paragraph(nextpara, next, null, null, selectEnd); r = placeParagraph(into, ft, nextpara, rect, 1, r.y+r.height + paraskip, 0); nextpara = next; if(r.y + r.height > size.height) break; } // And negative. r = ctr; while(true) { ZZCell prev = firstpara; firstpara = Nile2Iter.findStruct(firstpara, -1, false); if(firstpara == null) break; ld.detect(firstpara); ft = paragraph(firstpara, prev, null, null, null); beginningSentence[0] = true; r = placeParagraph(into, ft, firstpara, rect, -1, r.y - paraskip, 0); if(r.y < 0) break; } // into.dump(); Flob cursf = into.findFlob(null, accursed); // p("Cursf: "+cursf); if(cursf != null) ((SplitCellFlob1)cursf).addCurs(into, ZZCursorReal.getOffs(view), Color.red); } } // vim: set syntax=java :