#!../mofe --f
# This a more elaborate version of the postscript viewer using
# the XmNoteBook widget if available. 
#
# Note: this script needs perl to scan the postscript file!
#
# Authors: Peter Sylvester + Gustaf Neumann

fallbackResources topLevel \
    *mp1.Next-Page.accelerator          <Key>Next  \
    *mp1.Next-Page.acceleratorText      <PageDown> \
    *mp1.Next-Page.mnemonic             N          \
    *mp1.Previous-Page.accelerator      <Key>Prior \
    *mp1.Previous-Page.acceleratorText  <PageUp>   \
    *mp1.Previous-Page.mnemonic         P          \
    *mp1.Quit.accelerator               Ctrl<Key>c \
    *mp1.Quit.acceleratorText           Ctrl-C     \
    *mp1.Quit.mnemonic                  Q          \
    *mp1.Load.mnemonic                  L          \
    *background                         gainsboro  \
    *g.background                       gray97     \
    *g.foreground                       black      \
    *foreground                         black

mergeResources topLevel \
    *mp2*activateCallback "sV g orientation %w; refreshCurrentPage g" \
    *pages*browseSelectionCallback {nextPage g [expr %p-1]}

if {$ARGC == 2} { 
  set default_ps_doc [lindex $ARGV 1] 
}

XmMainWindow main topLevel  width 725 height 900

  XmMenuBar menu_bar main
  sV main menuBar menu_bar
    XmPulldownMenu mp1 menu_bar unmanaged
      XmPushButton Load      mp1 activateCallback "manageChild fs"
      XmPushButton Next-Page mp1 activateCallback "nextPage g +1"
      XmPushButton Previous-Page mp1 activateCallback "nextPage g -1"
     XmPushButton Quit      mp1 activateCallback quit
    XmCascadeButton File menu_bar subMenuId mp1  mnemonic F

    XmPulldownMenu mp2 menu_bar unmanaged
      XmPushButton portrait    mp2
      XmPushButton landscape   mp2
      XmPushButton upside-down mp2
      XmPushButton seascape    mp2
    XmCascadeButton Orientation menu_bar subMenuId mp2 mnemonic O

    XmPulldownMenu mp3 menu_bar unmanaged
      XmPushButton Zoom-in     mp3 activateCallback "zoom g 1.2"
      XmPushButton Zoom-out    mp3 activateCallback "zoom g 1/1.2"
      XmPushButton Center-Page mp3 activateCallback centerPage
    XmCascadeButton Zoom menu_bar subMenuId mp3  mnemonic Z

    XmPulldownMenu mph menu_bar unmanaged
      XmPushButton Help    mph activateCallback "manageChild helpbox"
      XmPushButton Version mph activateCallback "manageChild versionbox"
    XmCascadeButton Help menu_bar subMenuId mph  mnemonic H


#### we want to use this script with Motif 1.* AND Motif 2.0
#### there comes the code depending on the available widgets
if [string match "" [info command XmNotebook]] {
  # we have no XmNoteBook widget
  proc gsv {op args} {
    global GSV
    switch $op {
      setPageNumber {
	XmListSelectPos pages $args 0
      }
      setCurrentPage {
	setRawPage g $GSV(currentpage)
      }
      zoom {
	sV g \
	    xdpi [expr [gV g xdpi]*$args] \
	    ydpi [expr [gV g ydpi]*$args] 
      }
      create {
	XmForm form main
	XmScrolledList pages form \
	    bottomAttachment ATTACH_FORM topAttachment ATTACH_FORM \
	    width 65 resizable false
	XmScrolledWindow scrolled form \
	    scrollingPolicy AUTOMATIC \
	    bottomAttachment ATTACH_FORM topAttachment ATTACH_FORM \
	    leftAttachment ATTACH_WIDGET leftWidget pages \
	    rightAttachment ATTACH_FORM
	Ghostview g scrolled
      }
      setPageLabels {
	sV pages items $GSV(pagelabels) itemCount $GSV(maxpage)
      }
    }
  }
} else {
  # we have a XmNoteBook widget
  proc gsv {op args} {
    global GSV
    switch $op {
      setPageNumber {
	sV g pageNumber $args
      }
      setCurrentPage {
	sV gnotebook currentPageNumber $args
      }
      zoom {
	sV gnotebook \
	    width [expr int([gV gnotebook width]*$args)] \
	    height [expr int([gV gnotebook height]*$args)] 
      }
      create {
	XmScrolledWindow scrolled main scrollingPolicy AUTOMATIC
	XmNotebook gnotebook scrolled bindingType spiral \
	    pageChangedCallback {setRawPage g [expr %p-1]}
	Ghostview g gnotebook notebookChildType page pageNumber 1 \
	    xdpi 72 ydpi 72
      }
      setPageLabels {
	if [info exists GSV(tabs)] {
	  foreach tab $GSV(tabs) { destroyWidget $tab }
	  set GSV(tabs) {}
	}
	sV gnotebook firstPageNumber 1 lastPageNumber $GSV(maxpage)
	if {$GSV(maxpage) > 1} {
	  lappend GSV(tabs) [nbTab First major_tab 1]
	  set i 1
          foreach label $GSV(pagelabels) {
	    if [expr $i%10==0] {
	      lappend GSV(tabs) [nbTab $label major_tab $i]
	    }
	    lappend GSV(tabs) [nbTab $label minor_tab $i]
	    incr i
	  }
	  lappend GSV(tabs) [nbTab Last major_tab $GSV(maxpage)]
	}
      }
    }
  }
  proc nbTab {label tabType page} {
    return [XmPushButtonGadget tab$label gnotebook labelString $label \
	notebookChildType $tabType pageNumber $page]
  }
}


#### The code following here is supposed to be independend
#### from Motif 2.0
proc PS_Header {from length} {
  #puts stderr PS_HEADER
  global GSV
  set GSV(setup_start) $from
  set GSV(setup_len)   $length
}
proc PS_Page {page label from length} {
  #puts stderr "PS_PAGE $page $label $from $length"
  global GSV
  lappend GSV(pagedescr) "$from $length"
  if ![string compare $label label] {
    # those stupid Motif manuals!
    set label $page
  }
  lappend GSV(pagelabels) " $label "
}
proc PS_BoundingBox {llx lly urx ury} {
  #puts stderr "PS_BoundingBox $llx $lly $urx $ury"
  global GSV
  set GSV(boundingbox) "$llx $lly $urx $ury"
}

proc getPageInfo {f} {
  global GSV
  set script {
    $/ = "\n%%";
    $pos = -1;
    $currentPage = 0;
    while(<STDIN>) {
      if (/^Page:\s+(.+)\s+(\d+)\n/) {
	if ($currentPage) {
	  print "PS_Page $currentPage $currentLabel $currentOffset "
	  .($pos-$currentOffset)."\n";
	} else {
	  print "PS_Header 0 ".($pos-1)."\n";
	}
	$currentOffset = $pos;
	$currentPage = $2;
	$currentLabel = $1;
      } elsif (/^BoundingBox:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/ && 
	!$currentPage) {
	print "PS_BoundingBox $1 $2 $3 $4\n";	
      } elsif (/^Trailer/) {
	print "PS_Page $currentPage $currentLabel $currentOffset "
	    .($pos-$currentOffset)."\n";
      }
      $pos += length;
    }
  }
  if [catch {eval [exec perl -e $script < $f]}] {
    set GSV(pagelabels) " 1 "
  } else {
    set GSV(maxpage) [llength $GSV(pagelabels)]
  }
  # puts stderr pagelabels=$GSV(pagelabels)
}

proc setFile {f} {
  # puts stderr "setfile $f"
  global GSV

  set GSV(pagedescr)    {}
  set GSV(pagelabels)   {}
  set GSV(setup_start)  0
  set GSV(setup_len)    0
  set GSV(prolog_start) 0
  set GSV(prolog_len)   0
  set GSV(maxpage)      1
  set GSV(boundingbox) ""

  set label ""

  getPageInfo $f
  gsv setPageLabels

  # we count starting from 0
  incr GSV(maxpage) -1

  set GSV(filename) $f
  if [info exists GSV(filehandle)] {
    #    echo closing file
    close $GSV(filehandle)
    unset GSV(filehandle)
  }
  set GSV(currentpage) 0

  if {$GSV(maxpage) > 0} {
    # psscan was sucessful
    set GSV(filehandle) [open $f]
    sV g filename ""
    GhostviewDisableInterpreter g
    setRawPage g $GSV(currentpage)
    sV Previous-Page sensitive true
  } else {
    sV g filename $GSV(filename)
    sV Previous-Page sensitive false
  }
  gsv setCurrentPage 1
  if [string compare "" $GSV(boundingbox)] {
    sV g llx [lindex $GSV(boundingbox) 0] \
	lly [lindex $GSV(boundingbox) 1] \
	urx [lindex $GSV(boundingbox) 2] \
	ury [lindex $GSV(boundingbox) 3] 
  }
}

proc refreshCurrentPage {w} {
  global GSV
  setRawPage g $GSV(currentpage)
}

proc setRawPage {w page} {
  global GSV

  if ![info exists GSV(maxpage)] {
    return
  }
  if {$GSV(maxpage) > 1} {
    # puts stderr setRawPage=$page
    set page1 [expr $page+1]
    gsv setPageNumber $page1
    if [GhostviewIsInterpreterReady $w] {
      GhostviewNextPage $w
    } else {
      # puts stderr the-interpreter-is-NOT-ready
      GhostviewEnableInterpreter $w
      GhostviewSendPS $w $GSV(filehandle) $GSV(prolog_start) $GSV(prolog_len) 0
      GhostviewSendPS $w $GSV(filehandle) $GSV(setup_start)  $GSV(setup_len)  0
    }
    set pgdes [lindex $GSV(pagedescr) $page]
    GhostviewSendPS $w $GSV(filehandle) [lindex $pgdes 0] [lindex $pgdes 1] 0
    set GSV(currentpage) $page
  } else {
    GhostviewNextPage $w
  }
}

proc nextPage {w offset} {
  # puts stderr nextpage<$offset>
  global GSV
  if {$GSV(maxpage) > 1} {
    if [regexp {^[+-]} $offset] {
      # relative offset
      incr GSV(currentpage) $offset
    } else {
      # absolute value
      set GSV(currentpage) $offset
    }
    if {$GSV(currentpage) < 0} {
      set GSV(currentpage) 0
    } elseif {$GSV(currentpage) > $GSV(maxpage)} {
      set GSV(currentpage) $GSV(maxpage)
    }
    gsv setCurrentPage [expr $GSV(currentpage)+1]
  } else {
    setRawPage g $GSV(currentpage)
  }
}

proc zoom {w factor} {
  gsv zoom $factor
  refreshCurrentPage $w
  centerPage
}

proc centerScrollbar {w} {
  set max [gV $w maximum]
  set ss  [gV $w sliderSize]
  #puts stderr w-$w,max=$max,ss=$ss,gwidth=[gV g width],gheight=[gV g height]
  if [string compare $max $ss] { 
    sV $w value [expr ($max-$ss)/2] 
  }
}

proc centerPage {} {
  if ![isWidget scrolled] return
  centerScrollbar scrolled.VertScrollBar
  centerScrollbar scrolled.HorScrollBar
}

if [string match "" [info command Ghostview]] {
  set msg {
    This program can only be used, when mofe was compiled with Ghostview
    support. Your version of mofe supports only the following packages
  }
  append msg $PACKAGES
  XmLabel g main labelString $msg recomputeSize false width 500 height 300
  sV Load sensitive false
  XmMainWindowSetAreas main menu_bar NULL NULL NULL g
  sV menu_bar menuHelpWidget Help
  realize
} else {
  gsv create
  sV menu_bar menuHelpWidget Help
  realize
  if [info exists default_ps_doc] {
    setFile $default_ps_doc
  }
}

regexp {[^/]*$} $argv0 progName
XmMessageDialog versionbox mph unmanaged \
    dialogTitle "Motif Demo Program using the Ghostview widget" \
    okLabelString "Close" \
    messageString "$progName Version 0.00001, Jun 19, 1994"

XmMessageDialog helpbox mph unmanaged \
    dialogTitle "$progName Help" \
    okLabelString "Close" \
    messageString "This program is a simple demo program for the Ghostview Widget."

XmFileSelectionDialog fs mp1 unmanaged \
    dialogTitle "Select a Postscript File for Viewing" \
    okLabelString "Load" \
    pattern "*.ps" \
    autoUnmanage true \
    okCallback "setFile %s"

unmanageChild \
    [XmMessageBoxGetChild versionbox DIALOG_CANCEL_BUTTON] \
    [XmMessageBoxGetChild versionbox DIALOG_HELP_BUTTON]
unmanageChild \
    [XmMessageBoxGetChild helpbox DIALOG_CANCEL_BUTTON] \
    [XmMessageBoxGetChild helpbox DIALOG_HELP_BUTTON]
unmanageChild \
    [XmFileSelectionBoxGetChild fs DIALOG_HELP_BUTTON]
