/* This program started as a quick demonstration how to make a simple PDF reader (or actually a zoomer) with Hollywood, but after some more tuning it actually became quite useful little program, worth its own relase I think. This source code is public domain, you may use it in whatever way you wish. Please visit http://jpv.wmhost.com/jpv_software for more programs and stuff. */ @APPTITLE "RNOPDF" @APPAUTHOR "jPV/RNO" @APPCOPYRIGHT "(C) Copyright 2018 by RNO." @APPVERSION "$VER: RNOPDF 0.2 (20.10.18)" @APPDESCRIPTION "Quite tiny PDF viewer." @APPIDENTIFIER "com.wmhost.jpv.rnopdf" @REQUIRE "polybios" @DISPLAY {Title="RNOPDF", Width=240, Height=320, Color=#WHITE, Sizeable=True} ; Remember to change this when updating the program Const #VERSION="0.2" ; A separate quit function in case you'd want to do actions when quitting Function p_Quit() If settings.recent If pdfopen ; Update the recent list to remember the page number we were reading p_UpdateRecentList(FullPath(defdir$, deffile$)) ; Don't save the current settings, but the saved settings and the recent list settings_saved.recentfiles=CopyTable(settings.recentfiles) SavePrefs(settings_saved) EndIf Else If Not IsTableEmpty(settings_saved.recentfiles) settings_saved.recentfiles={} SavePrefs(settings_saved) EndIf EndIf End EndFunction ; A function to handle user input events, this will be called if you have installed event handlers at the bottom Function p_Input(msg) Switch msg.Action Case "OnMouseDown": Wait(20) If IsLeftMouse() Then p_Zoom() Case "OnWheelDown": p_Control("next") Case "OnWheelUp": p_Control("prev") Case "OnKeyUp": Switch msg.Key Case "PAGEDOWN": FallThrough Case "RIGHT": p_Control("next") Case "PAGEUP": FallThrough Case "LEFT": p_Control("prev") Case "HOME": p_Control("first") Case "END": p_Control("last") Case "UP": p_Control("jump", pdfpage-10) Case "DOWN": p_Control("jump", pdfpage+10) EndSwitch Case "OnRawKeyDown": Switch msg.Key Case "LCONTROL": FallThrough Case "RCONTROL": p_Zoom() EndSwitch Case "CloseWindow": p_Quit() Case "OnDropFile": p_Open(msg.DropFiles[0]) Case "OnMenuSelect": Switch msg.Item Case "open": p_Open() Case "exportcur": p_Export() Case "exportall": p_Export(True) Case "quit": p_Quit() Case "about": SystemRequest("About", "RNOPDF "..#VERSION.." by jPV/RNO\n\nhttp://jpv.wmhost.com/software", "OK", #REQICON_INFORMATION) Case "save": SavePrefs(settings) settings_saved=CopyTable(settings) Case "resize": settings.resize=msg.Selected Case "buffer": settings.buffer=msg.Selected Case "recent": settings.recent=msg.Selected If Not settings.recent And Not IsTableEmpty(settings_saved.recentfiles) settings_saved.recentfiles={} SavePrefs(settings_saved) EndIf Case "jump": Local j=StringRequest("Jump...", "Jump to page", pdfpage, #NUMERICAL) If j Then p_Control("jump", j) Case "jump-": p_Control("jump", pdfpage-10) Case "jump+": p_Control("jump", pdfpage+10) Default: If LeftStr(msg.Item, 4)="zoom" settings.zoom=ToNumber(UnrightStr(msg.Item, 4)) ElseIf LeftStr(msg.Item, 6)="recent" Local n=ToNumber(UnrightStr(msg.Item, 6)) p_Open(settings.recentfiles[n].file, settings.recentfiles[n].page) Else p_Control(msg.Item) EndIf EndSwitch EndSwitch EndFunction ; Custom page selection function which can be called from various places Function p_Control(cmd$, n) If pdfopen Local oldpage=pdfpage Switch cmd$ Case "next": If pdfpage1 Then pdfpage=pdfpage-1 Case "first": pdfpage=1 Case "last": pdfpage=pdfpages Case "jump": pdfpage=Limit(n, 1, pdfpages) Case "init": pdfpage=n Cls EndSwitch SetDisplayAttributes({Title="Loading..."}) If br_main Then FreeBrush(br_main) If pdfpage-oldpage<>1 And br_buffer FreeBrush(br_buffer) br_buffer=Nil EndIf If br_buffer br_main=br_buffer br_buffer=Nil Else br_main=pdf.GetBrush(1, pdfpage, Nil) EndIf If cmd$="init" And IsMenuItemSelected(1, "resize") ; Change the display size to the page size, but only if it fits on screen ChangeDisplaySize(Min(GetAttribute(#BRUSH, br_main, #ATTRWIDTH), GetAttribute(#DISPLAY, 0, #ATTRMAXWIDTH)),Min(GetAttribute(#BRUSH, br_main, #ATTRHEIGHT), GetAttribute(#DISPLAY, 0, #ATTRMAXHEIGHT))) EndIf p_Draw() If settings.buffer And pdfpagebw/bh t.w=Int(bw*dh/bh) t.h=dh t.x=Int((dw-t.w)/2) t.y=0 Else t.w=dw t.h=Int(bh*dw/bw) t.y=Int((dh-t.h)/2) t.x=0 EndIf Return(t) EndFunction ; Main display renderer/refresh function, will be called at window resizing etc Function p_Draw() If br_main Local s=p_Scale() ; Clearing some area if size has changed, with boxes rather than Cls again to squeeze few hundredths :) If prevw>s.w Or prevh>s.h Then BeginRefresh(True) If prevw>s.w And s.x>0 Box(0, 0, s.x, GetAttribute(#DISPLAY, 0, #ATTRHEIGHT), #WHITE) Box(s.x+s.w, 0, s.x+1, GetAttribute(#DISPLAY, 0, #ATTRHEIGHT), #WHITE) EndIf If prevh>s.h And s.y>0 Box(0, 0, GetAttribute(#DISPLAY, 0, #ATTRWIDTH), s.y, #WHITE) Box(0, s.y+s.h, GetAttribute(#DISPLAY, 0, #ATTRWIDTH), s.y+1, #WHITE) EndIf DisplayBrush(br_main, s.x, s.y, {Width=s.w, Height=s.h}) If prevw>s.w Or prevh>s.h Then EndRefresh() prevw=s.w prevh=s.h EndIf EndFunction ; Function for the zoom. Will get more streamlined with later Polybios versions. Function p_Zoom() If br_main Local mx=0 Local my=0 Local bx,by Local dw=GetAttribute(#DISPLAY, 0, #ATTRWIDTH) Local dh=GetAttribute(#DISPLAY, 0, #ATTRHEIGHT) Local s=p_Scale() Local bw=s.w*settings.zoom Local bh=s.h*settings.zoom Local ztmp=CreateBrush(Nil, bw, bh) SelectBrush(ztmp) DisplayBrush(br_main, 0, 0, {Width=bw, Height=bh}) EndSelect() While IsMidMouse() Or IsLeftMouse() Or IsKeyDown("LCONTROL") Or IsKeyDown("RCONTROL") If MouseX()<>mx Or MouseY()<>my mx=MouseX() my=MouseY() bx=mx-Int((mx-s.x)/s.w*bw) by=my-Int((my-s.y)/s.h*bh) BeginRefresh(True) ; Clearing only the needed area with boxes is about 2x faster than just using Cls If bx>0 Then Box(0, 0, bx, dh, #WHITE) If by>0 Then Box(0, 0, dw, by, #WHITE) If bx+bw\n" .. " FIRST\n" .. " PREV\n" .. " NEXT\n" .. " LAST\n" .. " PAGE \n" .. " EXPORT \n" .. " EXPORTALL \n" .. " QUIT\n" .. " GET \n" Return(helptxt$) Default: Return("Use the command 'HELP' for supported ARexx commands.") EndSwitch EndFunction ; Create an ARexx port on Amiga compatible platforms, and allow multiple instances vinfo=GetVersion() If MatchPattern(vinfo.platform, "AmigaOS*;MorphOS;WarpOS;AROS") Local portnum=0 ExitOnError(False) Repeat portnum=portnum+1 CreateRexxPort("RNOPDF." .. portnum) Until Not GetLastError() ExitOnError(True) SetDisplayAttributes({ScreenTitle="RNOPDF " .. #VERSION}) EndIf ; Initialize and set the default settings, and load saved settings settings={resize=1, zoom=2, buffer=1, recent=0, recentfiles={}} LoadPrefs(settings) ; Keeping the saved settings in a separate table to be able to save recentfiles without saving other settings, should think a prettier solution for this later... settings_saved=CopyTable(settings) p_InitMenu() ; Handle command line arguments args, argcount = GetCommandLine() If argcount>0 For Local k=0 To argcount-1 Switch UpperStr(args[k].arg) Case "FILE": p_Open(args[k].param) Case "DEFDIR": defdir$=args[k].param Default: Local helptxt$="Allowed arguments:\n".. " -file - Opens a file at startup.\n".. " -defdir - Sets the initial dir to open files.\n" StringToFile(helptxt$, "CONSOLE:") End EndSwitch Next EndIf ; Draw filled boxes later... SetFillStyle(#FILLCOLOR) ; Listen these events InstallEventHandler({SizeWindow=p_Draw, OnMouseDown=p_Input, OnMidMouseDown=p_Zoom, CloseWindow=p_Input, OnKeyUp=p_Input, OnRawKeyDown=p_Input, OnMenuSelect=p_Input, OnWheelDown=p_Input, OnWheelUp=p_Input, OnDropFile=p_Input, OnARexx=p_ARexx}) ; Main loop Repeat WaitEvent Forever