[go: up one dir, main page]

Menu

[r930]: / mcomix / zoom.py  Maximize  Restore  History

Download this file

166 lines (115 with data), 5.1 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
""" Handles zoom and fit of images in the main display area. """
from mcomix import constants
from mcomix.preferences import prefs
IDENTITY_ZOOM = 1.0
IDENTITY_ZOOM_LOG = 0
USER_ZOOM_LOG_SCALE1 = 4.0
MIN_USER_ZOOM_LOG = -20
MAX_USER_ZOOM_LOG = 12
class ZoomModel(object):
""" Handles zoom and fit modes. """
def __init__(self):
#: User zoom level.
self._user_zoom_log = IDENTITY_ZOOM_LOG
#: Image fit mode. Determines the base zoom level for an image by
#: calculating its maximum size.
self._fitmode = NoFitMode()
self._scale_up = False
def set_fit_mode(self, fitmode):
self._fitmode = fitmode
def get_scale_up(self):
return self._scale_up
def set_scale_up(self, scale_up):
self._scale_up = scale_up
def _set_user_zoom_log(self, zoom_log):
self._user_zoom_log = min(max(zoom_log, MIN_USER_ZOOM_LOG), MAX_USER_ZOOM_LOG)
def zoom_in(self):
self._set_user_zoom_log(self._user_zoom_log + 1)
def zoom_out(self):
self._set_user_zoom_log(self._user_zoom_log - 1)
def reset_user_zoom(self):
self._set_user_zoom_log(IDENTITY_ZOOM_LOG)
def get_zoomed_size(self, image_size, screen_size):
preferred_scale = self._fitmode.get_preferred_scale(
image_size, screen_size)
if (preferred_scale > IDENTITY_ZOOM and
(image_size[0] < screen_size[0] or
image_size[1] < screen_size[1]) and
not self.get_scale_up()):
preferred_scale = IDENTITY_ZOOM
return _scale_int(image_size,
preferred_scale * 2 ** (self._user_zoom_log / USER_ZOOM_LOG_SCALE1))
class FitMode(object):
""" Base class that handles scaling of images to predefined sizes. """
ID = -1
def get_preferred_scale(self, image_size, screen_size):
""" Returns the base image size (scaled to fit into screen_size,
depending on algorithm).
@param image_size: Tuple of (width, height), original image size
@param screen_size: Tuple of (width, height), available screen size
@return: Tuple of (width, height), scaled image size
"""
raise NotImplementedError()
@classmethod
def get_mode_identifier(cls):
""" Returns an unique identifier for a fit mode (for serialization) """
return cls.ID
@staticmethod
def create(fitmode):
for cls in (NoFitMode, BestFitMode, FitToWidthMode,
FitToHeightMode, FitToSizeMode):
if cls.get_mode_identifier() == fitmode:
return cls()
raise ValueError("No fit mode registered for identifier '%d'." % fitmode)
class NoFitMode(FitMode):
""" No automatic scaling depending on image size. """
ID = constants.ZOOM_MODE_MANUAL
def get_preferred_scale(self, image_size, screen_size):
if (image_size[0] < screen_size[0] and
image_size[1] < screen_size[1]):
return _calc_scale_both(image_size, screen_size)
return IDENTITY_ZOOM
class BestFitMode(FitMode):
""" Scales to fit both width and height into the screen frame. """
ID = constants.ZOOM_MODE_BEST
def get_preferred_scale(self, image_size, screen_size):
return _calc_scale_both(image_size, screen_size)
class FitToWidthMode(FitMode):
""" Scales images to fit into screen width. """
ID = constants.ZOOM_MODE_WIDTH
def get_preferred_scale(self, image_size, screen_size):
return _calc_scale_width(image_size, screen_size)
class FitToHeightMode(FitMode):
""" Scales images to fit into screen height. """
ID = constants.ZOOM_MODE_HEIGHT
def get_preferred_scale(self, image_size, screen_size):
return _calc_scale_height(image_size, screen_size)
class FitToSizeMode(FitMode):
""" Scales to a fix size (either height or width). """
ID = constants.ZOOM_MODE_SIZE
def __init__(self):
super(FitToSizeMode, self).__init__()
self.size = int(prefs['fit to size px'])
self.mode = prefs['fit to size mode']
def get_preferred_scale(self, image_size, screen_size):
if self.mode == constants.ZOOM_MODE_WIDTH:
side = image_size[0]
elif self.mode == constants.ZOOM_MODE_HEIGHT:
side = image_size[1]
else:
assert False, 'Invalid fit to size mode specified in preferences'
return _calc_scale(side, self.size)
def _scale_int(x, scale):
return int(round(x[0] * scale)), int(round(x[1] * scale))
def _calc_scale(length, desired_length):
""" Calculates the factor a number must be multiplied with to reach
a desired size. """
return float(desired_length) / float(length)
def _calc_scale_width(image_size, screen_size):
return _calc_scale(image_size[0], screen_size[0])
def _calc_scale_height(image_size, screen_size):
return _calc_scale(image_size[1], screen_size[1])
def _calc_scale_both(image_size, screen_size):
return min(_calc_scale_width(image_size, screen_size),
_calc_scale_height(image_size, screen_size))
# vim: expandtab:sw=4:ts=4