Commit | Line | Data |
---|---|---|
03feea07 FT |
1 | import threading, gtk, gio, gobject |
2 | import lib | |
3 | ||
4 | class notdone(Exception): pass | |
5 | ||
6 | class future(threading.Thread): | |
7 | prog = None | |
8 | ||
9 | def __init__(self): | |
10 | super(future, self).__init__() | |
11 | self._val = None | |
12 | self._exc = None | |
13 | self.start() | |
14 | ||
15 | def run(self): | |
16 | try: | |
17 | val = self.value() | |
18 | except Exception as e: | |
19 | self._exc = e | |
20 | else: | |
21 | self._val = [val] | |
22 | ||
23 | @property | |
24 | def val(self): | |
25 | if self._exc is not None: | |
26 | raise self._exc | |
27 | if self._val is None: | |
28 | raise notdone() | |
29 | return self._val[0] | |
30 | ||
31 | @property | |
32 | def done(self): | |
33 | return self._exc != None or self._val != None | |
34 | ||
35 | class imgload(future): | |
36 | def __init__(self, page): | |
37 | self.page = page | |
38 | self.st = None | |
39 | super(imgload, self).__init__() | |
40 | ||
41 | def value(self): | |
42 | buf = bytearray() | |
43 | with self.page.open() as st: | |
44 | self.p = 0 | |
45 | self.st = st | |
46 | while True: | |
47 | read = st.read(1024) | |
48 | if read == "": | |
49 | break | |
50 | self.p += len(read) | |
51 | buf.extend(read) | |
52 | self.st = None | |
53 | return gtk.gdk.pixbuf_new_from_stream(gio.memory_input_stream_new_from_data(str(buf))) | |
54 | ||
55 | @property | |
56 | def prog(self): | |
57 | if self.st is None or self.st.clen is None: | |
58 | return None | |
59 | return float(self.p) / float(self.st.clen) | |
60 | ||
61 | class pageview(gtk.Widget): | |
62 | def __init__(self, pixbuf): | |
63 | super(pageview, self).__init__() | |
64 | self.pixbuf = pixbuf | |
65 | self.zoomed = None, None | |
66 | self.fit = True | |
67 | self.zoom = 1.0 | |
68 | self.interp = gtk.gdk.INTERP_HYPER | |
69 | self.off = 0, 0 | |
70 | ||
71 | def get_osize(self): | |
72 | return self.pixbuf.get_width(), self.pixbuf.get_height() | |
73 | ||
74 | def get_asize(self): | |
75 | return self.allocation.width, self.allocation.height | |
76 | ||
77 | def do_realize(self): | |
78 | self.set_flags(self.flags() | gtk.REALIZED) | |
79 | alloc = self.allocation | |
80 | self.window = gtk.gdk.Window(self.get_parent_window(), | |
81 | width=alloc.width, height=alloc.height, | |
82 | window_type = gtk.gdk.WINDOW_CHILD, | |
83 | wclass = gtk.gdk.INPUT_OUTPUT, | |
84 | event_mask = self.get_events() | gtk.gdk.EXPOSURE_MASK | |
85 | ) | |
86 | self.window.set_user_data(self) | |
87 | self.style.attach(self.window) | |
88 | self.style.set_background(self.window, gtk.STATE_NORMAL) | |
89 | self.window.move_resize(*alloc) | |
90 | ||
91 | def do_unrealize(self): | |
92 | self.window.set_user_data(None) | |
93 | ||
94 | def do_size_request(self, req): | |
95 | req.width, req.height = self.get_osize() | |
96 | ||
97 | def fitzoom(self): | |
98 | w, h = self.get_osize() | |
99 | alloc = self.allocation | |
100 | return min(float(alloc.width) / float(w), float(alloc.height) / float(h)) | |
101 | ||
102 | def do_size_allocate(self, alloc): | |
103 | self.allocation = alloc | |
104 | if self.fit: | |
105 | self.zoom = self.fitzoom() | |
106 | if self.flags() & gtk.REALIZED: | |
107 | self.window.move_resize(*alloc) | |
108 | ||
109 | def get_zoomed(self): | |
110 | zoom = self.zoom | |
111 | pz, zbuf = self.zoomed | |
112 | if pz != zoom: | |
113 | w, h = self.get_osize() | |
114 | zbuf = self.pixbuf.scale_simple(int(w * zoom), int(h * zoom), self.interp) | |
115 | self.zoomed = zoom, zbuf | |
116 | return zbuf | |
117 | ||
118 | def get_zsize(self): | |
119 | zbuf = self.get_zoomed() | |
120 | return zbuf.get_width(), zbuf.get_height() | |
121 | ||
122 | def do_expose_event(self, event): | |
123 | aw, ah = self.get_asize() | |
124 | dw, dh = aw, ah | |
125 | zbuf = self.get_zoomed() | |
126 | zw, zh = self.get_zsize() | |
127 | ox, oy = self.off | |
128 | dx, dy = 0, 0 | |
129 | if zw < aw: | |
130 | dx = (aw - zw) / 2 | |
131 | dw = zw | |
132 | if zh < ah: | |
133 | dy = (ah - zh) / 2 | |
134 | dh = zh | |
135 | gc = self.style.fg_gc[gtk.STATE_NORMAL] | |
136 | self.window.draw_pixbuf(gc, zbuf, ox, oy, dx, dy, dw, dh) | |
137 | ||
138 | def set_off(self, off): | |
139 | aw, ah = self.get_asize() | |
140 | zw, zh = self.get_zsize() | |
141 | ox, oy = off | |
142 | ox, oy = int(ox), int(oy) | |
143 | if ox > zw - aw: ox = zw - aw | |
144 | if oy > zh - ah: oy = zh - ah | |
145 | if ox < 0: ox = 0 | |
146 | if oy < 0: oy = 0 | |
147 | self.off = ox, oy | |
148 | self.queue_draw() | |
149 | ||
150 | def set_zoom(self, zoom): | |
151 | if zoom is not None: zoom = float(zoom) | |
152 | aw, ah = self.get_asize() | |
153 | zw, zh = self.get_zsize() | |
154 | dw, dh = zw - aw, zh - ah | |
155 | ox, oy = self.off | |
156 | xa = float(ox) / float(dw) if dw > 0 else 0.5 | |
157 | ya = float(oy) / float(dh) if dh > 0 else 0.5 | |
158 | ||
159 | if zoom is None: | |
160 | self.fit = True | |
161 | self.zoom = self.fitzoom() | |
162 | else: | |
163 | self.fit = False | |
164 | self.zoom = zoom | |
165 | ||
166 | zw, zh = self.get_zsize() | |
167 | dw, dh = zw - aw, zh - ah | |
168 | ox = int(xa * dw) if dw > 0 else 0 | |
169 | oy = int(ya * dh) if dh > 0 else 0 | |
170 | self.set_off((ox, oy)) | |
171 | gobject.type_register(pageview) | |
172 | ||
43a12498 | 173 | class reader(gtk.Window): |
03feea07 | 174 | def __init__(self, manga): |
43a12498 FT |
175 | super(reader, self).__init__(gtk.WINDOW_TOPLEVEL) |
176 | self.connect("delete_event", lambda wdg, ev, data=None: False) | |
177 | self.connect("destroy", lambda wdg, data=None: self.quit()) | |
178 | self.connect("key_press_event", self.key) | |
179 | self.pfr = gtk.Frame(None) | |
180 | self.pfr.set_shadow_type(gtk.SHADOW_NONE) | |
181 | self.add(self.pfr) | |
182 | self.pfr.show() | |
183 | ||
184 | self.manga = manga | |
03feea07 FT |
185 | self.page = None |
186 | self.cursor = lib.cursor(manga) | |
187 | self.setpage(self.cursor.cur) | |
43a12498 FT |
188 | self.updtitle() |
189 | ||
190 | def setpage(self, page): | |
191 | if self.page is not None: | |
192 | self.pfr.remove(self.page) | |
193 | self.page = None | |
194 | if page is not None: | |
195 | with self.cursor.cur.open() as inp: | |
196 | pb = gtk.gdk.pixbuf_new_from_stream(gio.memory_input_stream_new_from_data(inp.read())) | |
197 | self.page = pageview(pb) | |
198 | self.pfr.add(self.page) | |
199 | self.page.show() | |
200 | ||
201 | def updtitle(self): | |
202 | self.set_title(u"Automanga \u2013 " + self.manga.name) | |
03feea07 FT |
203 | |
204 | @property | |
205 | def zoom(self): | |
206 | return self.page.zoom | |
207 | @zoom.setter | |
208 | def zoom(self, zoom): | |
209 | self.page.set_zoom(zoom) | |
210 | ||
211 | def pan(self, off): | |
212 | ox, oy = self.page.off | |
213 | px, py = off | |
214 | self.page.set_off((ox + px, oy + py)) | |
215 | ||
03feea07 FT |
216 | def key(self, wdg, ev, data=None): |
217 | if ev.keyval in [ord('Q'), ord('q'), 65307]: | |
218 | self.quit() | |
43a12498 FT |
219 | if ev.keyval in [ord('O'), ord('o')]: |
220 | self.zoom = 1.0 | |
221 | elif ev.keyval in [ord('P'), ord('p')]: | |
222 | self.zoom = None | |
223 | elif ev.keyval in [ord('[')]: | |
224 | self.zoom = min(self.zoom * 1.25, 3) | |
225 | elif ev.keyval in [ord(']')]: | |
226 | self.zoom /= 1.25 | |
227 | elif ev.keyval in [ord('h')]: | |
228 | self.pan((-100, 0)) | |
229 | elif ev.keyval in [ord('j')]: | |
230 | self.pan((0, 100)) | |
231 | elif ev.keyval in [ord('k')]: | |
232 | self.pan((0, -100)) | |
233 | elif ev.keyval in [ord('l')]: | |
234 | self.pan((100, 0)) | |
235 | elif ev.keyval in [ord('H')]: | |
236 | self.page.set_off((0, self.page.off[1])) | |
237 | elif ev.keyval in [ord('J')]: | |
238 | self.page.set_off((self.page.off[0], self.page.get_asize()[1])) | |
239 | elif ev.keyval in [ord('K')]: | |
240 | self.page.set_off((self.page.off[1], 0)) | |
241 | elif ev.keyval in [ord('L')]: | |
242 | self.page.set_off((self.page.get_asize()[0], self.page.off[1])) | |
243 | elif ev.keyval in [ord(' ')]: | |
244 | self.setpage(self.cursor.next()) | |
245 | elif ev.keyval in [65288]: | |
246 | self.setpage(self.cursor.prev()) | |
03feea07 FT |
247 | |
248 | def quit(self): | |
249 | self.hide() | |
43a12498 | 250 | gobject.type_register(reader) |