added Makefile self-dependency
[swftools.git] / wx / gui / gmain.py
1 #!/usr/bin/env python
2 # -*- coding: UTF-8 -*-
3 #
4 # gpdf2swf.py
5 # graphical user interface for pdf2swf
6 #
7 # Part of the swftools package.
8
9 # Copyright (c) 2008,2009 Matthias Kramm <kramm@quiss.org> 
10 #
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 # GNU General Public License for more details.
20 #
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
24
25 from __future__ import division
26 import os
27 import wx
28 from wx.lib.pubsub import Publisher
29 from lib.embeddedimage import PyEmbeddedImage
30 import thread
31 import time
32 import lib.images as images
33
34 ICON_SIZE = 64
35
36 ID_INVERT_SELECTION = wx.NewId()
37 ID_SELECT_ODD = wx.NewId()
38 ID_SELECT_EVEN = wx.NewId()
39 ID_ONE_PAGE_PER_FILE = wx.NewId()
40
41 ID_DOC_INFO = wx.NewId()
42 ID_PREVIEW_TYPE = wx.NewId()
43
44
45 class _AppendThumbnailThread:
46     def __init__(self, win, thumbs):
47         self.__win = win
48         self.__thumbs = thumbs
49
50     def Start(self):
51         self.__keep_running = self.running = True
52         thread.start_new_thread(self.Run, ())
53
54     def IsRunning(self):
55         return self.running
56
57     def Stop(self):
58         self.__keep_running = False
59
60     def Run(self):
61         thumbs = self.__thumbs
62         different_sizes = False
63         for pos, thumb in enumerate(thumbs):
64             if pos == 0:
65                 width, height = thumb.width, thumb.height
66             else:
67                 if not different_sizes:
68                     if abs(width - thumb.width) > 2 or \
69                        abs(height - thumb.height) > 2:
70                            different_sizes = True
71                            wx.CallAfter(Publisher.sendMessage, "DIFF_SIZES")
72
73             wx.CallAfter(self.__win.AppendThumbnail, pos,
74                          thumb.asImage(ICON_SIZE, ICON_SIZE), thumb)
75             wx.CallAfter(Publisher.sendMessage, "THUMBNAIL_ADDED",
76                                                 {'pagenr':pos+1,})
77             time.sleep(.01)
78             if not self.__keep_running:
79                 break
80
81         wx.CallAfter(Publisher.sendMessage, "THUMBNAIL_DONE")
82         time.sleep(.10)
83
84         self.running = False
85
86 class FileDropTarget(wx.FileDropTarget):
87     def __init__(self, window):
88         wx.FileDropTarget.__init__(self)
89         self.window = window
90
91     def OnDropFiles(self, x, y, filenames):
92         if len(filenames) == 1:
93             Publisher.sendMessage("FILE_DROPED",
94                                    {'filename': filenames[0]}
95                                  )
96         else:
97             Publisher.sendMessage("FILES_DROPED",
98                                    {'filenames': filenames}
99                                  )
100
101 class PagePreviewWindow(wx.ScrolledWindow):
102     def __init__(self, parent):
103         wx.ScrolledWindow.__init__(self, parent)
104         self.SetBackgroundColour('grey')
105         self.SetScrollRate(20, 20)
106
107         self.__buffer = wx.EmptyBitmap(1, 1)
108
109         self.Bind(wx.EVT_PAINT, self.__OnPaint)
110
111     def DisplayPage(self, page):
112         thread.start_new_thread(self.__DisplayPageThread, (page,))
113
114     def Clear(self):
115         self.__buffer = wx.EmptyBitmap(1, 1)
116         self.Refresh()
117
118     def __OnPaint(self, event):
119         dc = wx.BufferedPaintDC(self, self.__buffer, wx.BUFFER_VIRTUAL_AREA)
120
121     def __DisplayPage(self, w, h, page):
122         self.SetVirtualSize((w, h))
123         self.__buffer = wx.EmptyBitmap(w+2, h+2)
124         dc = wx.BufferedDC(None, self.__buffer)
125         dc.Clear()
126         dc.DrawRectangle(0, 0, w+2, h+2)
127         #dc.DrawBitmap(wx.BitmapFromBuffer(w, h, page), 1, 1, True)
128         dc.DrawBitmap(wx.BitmapFromImage(
129                        wx.ImageFromData(w, h, page)), 1, 1, True)
130
131         self.Refresh()
132
133     def __DisplayPageThread(self, page):
134         w = page['width']
135         h = page['height']
136         time.sleep(.02)
137         page = page["page"].asImage(w, h)
138         wx.CallAfter(self.__DisplayPage, w, h, page)
139
140
141 class PageListCtrl(wx.ListView):
142     def __init__(self, parent):
143         wx.ListView.__init__(self, parent, style=wx.LC_ICON)
144         self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
145
146     def OnContextMenu(self, event):
147         if self.GetItemCount():
148             menu = wx.Menu()
149             menu.Append(wx.ID_SELECTALL, u"Select All\tCTRL-A")
150             menu.AppendSeparator()
151             menu.Append(wx.ID_SAVE, u"Save SWF (all pages)\tCTRL-W")
152             menu.Append(wx.ID_SAVEAS, u"Save SWF (selected pages)\tCTRL-S")
153             self.PopupMenu(menu)
154             menu.Destroy()
155
156     def DisplayEmptyThumbnails(self, pages):
157         self.DeleteAllItems()
158         self.imglist = wx.ImageList(ICON_SIZE, ICON_SIZE, mask=True)
159         self.AssignImageList(self.imglist, wx.IMAGE_LIST_NORMAL)
160         bmp = images.getblankBitmap()
161         for pos in range(pages):
162             self.imglist.Add(bmp)
163             self.InsertImageStringItem(pos, u"Page %s" % (pos+1), pos)
164
165     def DisplayThumbnails(self, thumbs):
166         t = _AppendThumbnailThread(self, thumbs)
167         t.Start()
168         return t
169
170     def AppendThumbnail(self, pos, thumb, page):
171         #bmp = wx.BitmapFromBuffer(ICON_SIZE, ICON_SIZE, thumb)
172         bmp = wx.BitmapFromImage(
173                        wx.ImageFromData(ICON_SIZE, ICON_SIZE,
174                                         thumb))
175         self.imglist.Replace(pos, bmp)
176         self.SetItemText(pos, u"Page %s\n(%sx%s)" % (pos+1,
177                                    page.width, page.height))
178         if pos == 0:
179             wx.CallAfter(self.Select, 0)
180         self.RefreshItem(pos)
181
182
183 class StatusBar(wx.StatusBar):
184     def __init__(self, parent):
185         wx.StatusBar.__init__(self, parent, -1)
186
187         self.sizeChanged = False
188         self.Bind(wx.EVT_SIZE, self.OnSize)
189         self.Bind(wx.EVT_IDLE, self.OnIdle)
190
191         self.gauge = wx.Gauge(self)
192
193         bmp = images.getstopBitmap()
194         self.btn_cancel = wx.BitmapButton(self, bitmap=bmp,
195                                        style = wx.NO_BORDER)
196         self.gauge.Hide()
197         self.btn_cancel.Hide()
198         
199         self.Reposition()
200
201     def SetGaugeValue(self, value):
202         if value == 0:
203             self.gauge.Hide()
204             self.btn_cancel.Hide()
205         self.gauge.SetValue(value)
206
207     def SetGaugeRange(self, pages):
208         self.gauge.Show()
209         self.btn_cancel.Show()
210         self.gauge.SetRange(pages)
211
212     def OnSize(self, evt):
213         self.Reposition()
214         self.sizeChanged = True
215
216     def OnIdle(self, evt):
217         if self.sizeChanged:
218             self.Reposition()
219
220     def Reposition(self):
221         rect = self.GetFieldRect(0)
222         of = rect.width // 1.5
223         self.gauge.SetPosition((rect.x+of , rect.y+2))
224         self.gauge.SetSize((rect.width-of-24, rect.height-4))
225         self.btn_cancel.SetPosition((rect.width-22, rect.y+1))
226         self.btn_cancel.SetSize((22, rect.height-2))
227         self.sizeChanged = False
228
229
230 class PdfFrame(wx.Frame):
231     def __init__(self):
232         wx.Frame.__init__(self, None, size=(750,550), title=u"gpdf2swf")
233
234         icon = self.__MakeIcon()
235         self.SetIcon(icon)
236         self.__CreateMenu()
237         self.__CreateToolbar()
238         self.statusbar = StatusBar(self)
239         self.SetStatusBar(self.statusbar)
240
241         dt = FileDropTarget(self)
242         self.SetDropTarget(dt)
243
244         hsplit = wx.SplitterWindow(self, style=wx.SP_3D|wx.SP_LIVE_UPDATE)
245         self.page_list = PageListCtrl(hsplit)
246         self.page_preview = PagePreviewWindow(hsplit)
247         hsplit.SplitVertically(self.page_list, self.page_preview,
248                                sashPosition=ICON_SIZE*2)
249         hsplit.SetMinimumPaneSize(ICON_SIZE*2)
250
251     def __MakeIcon(self):
252         img = images.getgpdf2swfImage()
253         if "wxMSW" in wx.PlatformInfo:
254             img = img.Scale(16, 16)
255         #elif "wxGTK" in wx.PlatformInfo:
256         #    img = img.Scale(22, 22)
257         # wxMac and wxGTK???? can be any size up to 128x128,
258         # so leave the source img alone....
259         icon = wx.IconFromBitmap(img.ConvertToBitmap())
260         return icon
261
262     def __CreateMenu(self):
263         menubar = wx.MenuBar()
264
265         menu_recent = wx.Menu()
266         menu_save = wx.Menu()
267         menu_save.AppendCheckItem(ID_ONE_PAGE_PER_FILE, u"One Page Per File")
268         menu_save.AppendSeparator()
269         menu_save.Append(wx.ID_SAVE, u"All Pages\tCTRL-W",
270                                 u"Save all pages")
271         menu_save.Append(wx.ID_SAVEAS, u"Selected Pages\tCTRL-S",
272                                   u"Save selected pages")
273
274         menu = wx.Menu()
275         menu.Append(wx.ID_OPEN, u"Open PDF\tCTRL-O", u"Open a PDF document")
276         menu.AppendMenu(wx.ID_ANY, u"Save SWF", menu_save)
277         menu.AppendSeparator()
278         menu.AppendMenu(wx.ID_ANY, u"Recent", menu_recent)
279         menu.AppendSeparator()
280         menu.Append(wx.ID_EXIT, u"Exit\tCTRL-Q")
281         menubar.Append(menu, u"&File")
282
283         self.filehistory = wx.FileHistory()
284         self.filehistory.UseMenu(menu_recent)
285
286         menu = wx.Menu()
287         menu.Append(wx.ID_SELECTALL, u"Select All\tCTRL-A",
288                                      u"Select all pages")
289         menu.Append(ID_INVERT_SELECTION, u"Invert Selection",
290                                          u"Invert current selection")
291         menu.Append(ID_SELECT_ODD, u"Select Odd",
292                                    u"Select odd pages")
293         menu.Append(ID_SELECT_EVEN, u"Select Even",
294                                     u"Select even pages")
295         menu.AppendSeparator()
296         menu.Append(wx.ID_PREFERENCES, u"Options\tCTRL-R",
297                                        u"Show options dialog")
298         menubar.Append(menu, u"&Edit")
299
300         menu = wx.Menu()
301         menu.Append(wx.ID_ZOOM_IN, u"Zoom In\tCTRL-+")
302         menu.Append(wx.ID_ZOOM_OUT, u"Zoom Out\tCTRL--")
303         menu.Append(wx.ID_ZOOM_100, u"Normal Size\tCTRL-0")
304         menu.Append(wx.ID_ZOOM_FIT, u"Fit\tCTRL-1")
305         menu.AppendSeparator()
306         menu.Append(ID_DOC_INFO, u"Document Info\tCTRL-I")
307         menubar.Append(menu, u"&View")
308
309         menu = wx.Menu()
310         menu.Append(wx.ID_ABOUT, u"About")
311         menubar.Append(menu, u"&Help")
312         self.SetMenuBar(menubar)
313
314     def __CreateToolbar(self):
315         tsize = (16,16)
316         wxart = wx.ArtProvider.GetBitmap
317         self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL |
318                                           wx.NO_BORDER | wx.TB_FLAT)
319         self.toolbar.AddSimpleTool(wx.ID_OPEN,
320                                    wxart(wx.ART_FILE_OPEN,
321                                          wx.ART_TOOLBAR, tsize),
322                                    u"Open")
323         self.toolbar.AddSimpleTool(wx.ID_SAVE,
324                                    wxart(wx.ART_FILE_SAVE,
325                                          wx.ART_TOOLBAR, tsize),
326                                    u"Save SWF (all pages)")
327         self.toolbar.AddSeparator()
328
329         self.toolbar.AddSimpleTool(wx.ID_PREFERENCES,
330                                    wxart(wx.ART_LIST_VIEW,
331                                          wx.ART_TOOLBAR, tsize),
332                                    u"Options")
333         self.toolbar.AddSeparator()
334
335         self.toolbar.AddSimpleTool(ID_DOC_INFO,
336                                    wxart(wx.ART_TIP,
337                                          wx.ART_TOOLBAR, tsize),
338                                    u"Document Info")
339
340         self.toolbar.AddSeparator()
341
342         self.toolbar_preview_type = wx.Choice(
343                 self.toolbar, ID_PREVIEW_TYPE,
344                 choices=["everything to bitmaps",
345                          "fonts to fonts, everything else to bitmaps",
346                          "polygons to polygons and fonts to fonts"],
347                 size=(350,-1), style=wx.CB_DROPDOWN
348                 )
349         # I'm not sure about the utility of this, so Show False
350         self.toolbar_preview_type.Show(False)
351         self.toolbar.AddControl(self.toolbar_preview_type)
352
353         self.toolbar.Realize()
354