]>
Commit | Line | Data |
---|---|---|
cccce1a6 RD |
1 | #---------------------------------------------------------------------- |
2 | # Name: wx.lib.ticker | |
3 | # Purpose: A news-ticker style scrolling text control | |
4 | # | |
5 | # Author: Chris Mellon | |
6 | # | |
7 | # Created: 29-Aug-2004 | |
8 | # RCS-ID: $Id$ | |
9 | # Copyright: (c) 2004 by Chris Mellon | |
10 | # Licence: wxWindows license | |
11 | #---------------------------------------------------------------------- | |
12 | ||
13 | """News-ticker style scrolling text control | |
14 | ||
9f4cc34f RD |
15 | * Can scroll from right to left or left to right. |
16 | ||
17 | * Speed of the ticking is controlled by two parameters: | |
18 | ||
19 | - Frames per Second(FPS): How many times per second the ticker updates | |
20 | ||
21 | - Pixels per Frame(PPF): How many pixels the text moves each update | |
22 | ||
23 | Low FPS with high PPF will result in "jumpy" text, lower PPF with higher FPS | |
24 | is smoother (but blurrier and more CPU intensive) text. | |
cccce1a6 RD |
25 | """ |
26 | ||
27 | import wx | |
28 | ||
29 | #---------------------------------------------------------------------- | |
30 | ||
31 | class Ticker(wx.PyControl): | |
32 | def __init__(self, | |
33 | parent, | |
34 | id=-1, | |
35 | text=wx.EmptyString, #text in the ticker | |
36 | fgcolor = wx.BLACK, #text/foreground color | |
37 | bgcolor = wx.WHITE, #background color | |
38 | start=True, #if True, the ticker starts immediately | |
39 | ppf=2, #pixels per frame | |
40 | fps=20, #frames per second | |
41 | direction="rtl", #direction of ticking, rtl or ltr | |
42 | pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.NO_BORDER, | |
43 | name="Ticker" | |
44 | ): | |
45 | wx.PyControl.__init__(self, parent, id=id, pos=pos, size=size, style=style, name=name) | |
46 | self.timer = wx.Timer(owner=self) | |
47 | self._extent = (-1, -1) #cache value for the GetTextExtent call | |
48 | self._offset = 0 | |
49 | self._fps = fps #frames per second | |
50 | self._ppf = ppf #pixels per frame | |
51 | self.SetDirection(direction) | |
52 | self.SetText(text) | |
53 | self.SetBestFittingSize(size) | |
54 | self.SetForegroundColour(fgcolor) | |
55 | self.SetBackgroundColour(bgcolor) | |
56 | wx.EVT_TIMER(self, -1, self.OnTick) | |
57 | wx.EVT_PAINT(self, self.OnPaint) | |
58 | wx.EVT_ERASE_BACKGROUND(self, self.OnErase) | |
59 | if start: | |
60 | self.Start() | |
61 | ||
62 | ||
63 | def Stop(self): | |
64 | """Stop moving the text""" | |
65 | self.timer.Stop() | |
66 | ||
67 | ||
68 | def Start(self): | |
69 | """Starts the text moving""" | |
70 | if not self.timer.IsRunning(): | |
71 | self.timer.Start(1000 / self._fps) | |
72 | ||
73 | ||
74 | def IsTicking(self): | |
75 | """Is the ticker ticking? ie, is the text moving?""" | |
76 | return self.timer.IsRunning() | |
77 | ||
78 | ||
79 | def SetFPS(self, fps): | |
80 | """Adjust the update speed of the ticker""" | |
81 | self._fps = fps | |
82 | self.Stop() | |
83 | self.Start() | |
84 | ||
85 | ||
86 | def GetFPS(self): | |
87 | """Update speed of the ticker""" | |
88 | return self._fps | |
89 | ||
90 | ||
91 | def SetPPF(self, ppf): | |
92 | """Set the number of pixels per frame the ticker moves - ie, how "jumpy" it is""" | |
93 | self._ppf = ppf | |
94 | ||
95 | ||
96 | def GetPPF(self): | |
97 | """Pixels per frame""" | |
98 | return self._ppf | |
99 | ||
100 | ||
101 | def SetFont(self, font): | |
102 | self._extent = (-1, -1) | |
103 | wx.Control.SetFont(self, font) | |
104 | ||
105 | ||
106 | def SetDirection(self, dir): | |
107 | """Sets the direction of the ticker: right to left(rtl) or left to right (ltr)""" | |
108 | if dir == "ltr" or dir == "rtl": | |
109 | if self._offset <> 0: | |
110 | #Change the offset so it's correct for the new direction | |
111 | self._offset = self._extent[0] + self.GetSize()[0] - self._offset | |
112 | self._dir = dir | |
113 | else: | |
114 | raise TypeError | |
115 | ||
116 | ||
117 | def GetDirection(self): | |
118 | return self._dir | |
119 | ||
120 | ||
121 | def SetText(self, text): | |
122 | """Set the ticker text.""" | |
123 | self._text = text | |
124 | self._extent = (-1, -1) | |
125 | if not self._text: | |
126 | self.Refresh() #Refresh here to clear away the old text. | |
127 | ||
128 | ||
129 | def GetText(self): | |
130 | return self._text | |
131 | ||
132 | ||
133 | def UpdateExtent(self, dc): | |
134 | """Updates the cached text extent if needed""" | |
135 | if not self._text: | |
136 | self._extent = (-1, -1) | |
137 | return | |
138 | if self._extent == (-1, -1): | |
139 | self._extent = dc.GetTextExtent(self.GetText()) | |
140 | ||
141 | ||
142 | def DrawText(self, dc): | |
143 | """Draws the ticker text at the current offset using the provided DC""" | |
144 | dc.SetTextForeground(self.GetForegroundColour()) | |
145 | dc.SetFont(self.GetFont()) | |
146 | self.UpdateExtent(dc) | |
147 | if self._dir == "ltr": | |
148 | offx = self._offset - self._extent[0] | |
149 | else: | |
150 | offx = self.GetSize()[0] - self._offset | |
151 | offy = (self.GetSize()[1] - self._extent[1]) / 2 #centered vertically | |
152 | dc.DrawText(self._text, offx, offy) | |
153 | ||
154 | ||
155 | def OnTick(self, evt): | |
156 | self._offset += self._ppf | |
157 | w1 = self.GetSize()[0] | |
158 | w2 = self._extent[0] | |
159 | if self._offset >= w1+w2: | |
160 | self._offset = 0 | |
161 | self.Refresh() | |
162 | ||
163 | ||
164 | def OnPaint(self, evt): | |
165 | dc = wx.BufferedPaintDC(self) | |
166 | brush = wx.Brush(self.GetBackgroundColour()) | |
167 | dc.SetBackground(brush) | |
168 | dc.Clear() | |
169 | self.DrawText(dc) | |
170 | ||
171 | ||
172 | def OnErase(self, evt): | |
173 | """Noop because of double buffering""" | |
174 | pass | |
175 | ||
176 | ||
177 | def AcceptsFocus(self): | |
178 | """Non-interactive, so don't accept focus""" | |
179 | return False | |
180 | ||
181 | ||
182 | def DoGetBestSize(self): | |
183 | """Width we don't care about, height is either -1, or the character | |
184 | height of our text with a little extra padding | |
185 | """ | |
186 | if self._extent == (-1, -1): | |
187 | if not self._text: | |
188 | h = self.GetCharHeight() | |
189 | else: | |
190 | h = self.GetTextExtent(self.GetText())[1] | |
191 | else: | |
192 | h = self._extent[1] | |
193 | return (100, h+5) | |
194 | ||
195 | ||
196 | def ShouldInheritColours(self): | |
197 | """Don't get colours from our parent...""" | |
198 | return False | |
199 | ||
200 | ||
201 | ||
202 | #testcase/demo | |
203 | if __name__ == '__main__': | |
204 | app = wx.PySimpleApp() | |
205 | f = wx.Frame(None) | |
206 | p = wx.Panel(f) | |
207 | t = Ticker(p, text="Some sample ticker text") | |
208 | #set ticker properties here if you want | |
209 | s = wx.BoxSizer(wx.VERTICAL) | |
210 | s.Add(t, flag=wx.GROW, proportion=0) | |
211 | p.SetSizer(s) | |
212 | f.Show() | |
213 | app.MainLoop() | |
214 | ||
215 |