This commit was manufactured by cvs2svn to create tag 'wxPy_2_3_3_1'.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/tags/wxPy_2_3_3_1@17271 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
Building wxPython on Mac OS X
|
||||
-----------------------------
|
||||
|
||||
NOTE: OS X support is HIGHLY EXPERIMENTAL at this time. Most things
|
||||
are working now, but a few still don't. I know about most of
|
||||
them and am addressing them as I have time. If you have any
|
||||
ideas about a fix for the stuff that's still broken then
|
||||
please persue them and send the fixes to me.
|
||||
NOTE: OS X support is EXPERIMENTAL at this time. Most things are
|
||||
working now, but a few still don't. I know about most of them
|
||||
and am addressing them as I have time. If you have any ideas
|
||||
about a fix for the stuff that's still broken then please
|
||||
persue them and send the fixes to me.
|
||||
|
||||
|
||||
These are the steps I have used for building wxPython on Mac OS X 10.1
|
||||
@@ -14,13 +14,14 @@ that you know your way around a command line and that you know how to
|
||||
get things from various CVS repositories as needed.
|
||||
|
||||
|
||||
1. Python 2.2 is required. There is a disk image with an installer
|
||||
package in the wxPython Sourceforge download area, in this group:
|
||||
1. "MachoPython" 2.2 is required. There is a disk image with an
|
||||
installer package in the wxPython Sourceforge download area, in
|
||||
this group:
|
||||
|
||||
http://sourceforge.net/project/showfiles.php?group_id=10718&release_id=84730
|
||||
|
||||
If, for some reason you need to build your own Python, get the
|
||||
source from www.python.org and follow theinstructions in the
|
||||
source from www.python.org and follow the instructions in the
|
||||
Mac/OSX/README file to build and install Python.app and the
|
||||
Python.framework.
|
||||
|
||||
@@ -33,8 +34,8 @@ get things from various CVS repositories as needed.
|
||||
sudo ln -s python2.2 python
|
||||
|
||||
Also, if you create a /usr/local/bin/pythonw script like the
|
||||
following then you can run Python GUI apps (like wxPython) directly
|
||||
from the command line:
|
||||
following then you can run Python GUI apps (like wxPython apps)
|
||||
directly from the command line:
|
||||
|
||||
#!/bin/sh
|
||||
exec /Applications/Python.app/Contents/MacOS/python $@
|
||||
@@ -45,13 +46,15 @@ get things from various CVS repositories as needed.
|
||||
|
||||
If you would like to make a MachoPython installer from what you
|
||||
built then you may want to look at the scripts I use to do it
|
||||
located in wxPython/distrib/mac/buildPython.
|
||||
located in wxPython/distrib/mac/buildPython in CVS.
|
||||
|
||||
One last thing, make sure that /usr/local/bin is in your PATH
|
||||
environment variable.
|
||||
|
||||
|
||||
2. In a wxWindows CVS tree make a build directory.
|
||||
2. In a wxWindows CVS tree make a build directory. (You can also use
|
||||
a CVS snapshot located in http://wxwindows.org/snapshots/ or the
|
||||
released wxPythonSrc-*.tr.gz archive.)
|
||||
|
||||
cd ~/proj/wxWindows # or wherever you put it
|
||||
mkdir build
|
||||
|
@@ -249,7 +249,9 @@ C. Change to the root wxPython directory and look at the setup.py
|
||||
and shadow python files.
|
||||
|
||||
IN_CVS_TREE If you are using the CVS version of the
|
||||
wxWindows and wxPython sources then you will
|
||||
wxWindows and wxPython sources, or a combined
|
||||
source archive from the CVS snapshots or the
|
||||
distributed wxPythonSrc-*.tar.gz then you will
|
||||
need to set this flag to non-zero. This is
|
||||
needed because some source files from the
|
||||
wxWindows tree are copied to be under the
|
||||
@@ -257,9 +259,6 @@ C. Change to the root wxPython directory and look at the setup.py
|
||||
With this flag set then setup.py will
|
||||
automatically keep these copied sources up to
|
||||
date if the original version is ever updated.
|
||||
If you are using the tar.gz version of the
|
||||
Python sources then these copied sources are
|
||||
already present in your source tree.
|
||||
|
||||
|
||||
D. To build and install wxPython you simply need to execute the
|
||||
|
@@ -246,18 +246,17 @@ B. Change to the root wxPython directory and look at the setup.py
|
||||
will be executed to regenerate the wrapper C++
|
||||
and shadow python files.
|
||||
|
||||
IN_CVS_TREE If you are using the CVS version of the
|
||||
wxWindows and wxPython sources then you will
|
||||
need to set this flag to non-zero. This is
|
||||
needed because some source files from the
|
||||
wxWindows tree are copied to be under the
|
||||
wxPython tree in order to keep Distutils happy.
|
||||
With this flag set then setup.py will
|
||||
automatically keep these copied sources up to
|
||||
date if the original version is ever updated.
|
||||
If you are using the tar.gz version of the
|
||||
Python sources then these copied sources are
|
||||
already present in your source tree.
|
||||
IN_CVS_TREE If you are using the CVS version of the
|
||||
wxWindows and wxPython sources, or a combined
|
||||
source archive from the CVS snapshots or the
|
||||
distributed wxPythonSrc-*.tar.gz then you will
|
||||
need to set this flag to non-zero. This is
|
||||
needed because some source files from the
|
||||
wxWindows tree are copied to be under the
|
||||
wxPython tree in order to keep Distutils happy.
|
||||
With this flag set then setup.py will
|
||||
automatically keep these copied sources up to
|
||||
date if the original version is ever updated.
|
||||
|
||||
|
||||
C. To build and install wxPython you simply need to execute the
|
||||
|
@@ -174,6 +174,9 @@ Added wxXmlResourceHandler which allows you to create custom handlers
|
||||
for nonstandard class types in XRC resources. See the demo for an
|
||||
example.
|
||||
|
||||
Added wxPython.lib.mixins.rubberband module from Robb Shecter.
|
||||
|
||||
Added wxTimeCtrl from Will Sadkin.
|
||||
|
||||
|
||||
|
||||
|
@@ -3,5 +3,5 @@
|
||||
wx.wxStyledTextEventPtr = wxStyledTextEventPtr
|
||||
wx.wxStyledTextCtrlPtr = wxStyledTextCtrlPtr
|
||||
|
||||
|
||||
wxSTC_CARET_CENTER = wxSTC_CARET_STRICT
|
||||
# This constant no longer exists in Scintilla, but I'll put it here for a while to avoid disrupting user code...
|
||||
wxSTC_CARET_CENTER = 0
|
||||
|
@@ -1819,5 +1819,5 @@ wxEVT_STC_ZOOM = stc_c.wxEVT_STC_ZOOM
|
||||
wx.wxStyledTextEventPtr = wxStyledTextEventPtr
|
||||
wx.wxStyledTextCtrlPtr = wxStyledTextCtrlPtr
|
||||
|
||||
|
||||
wxSTC_CARET_CENTER = wxSTC_CARET_STRICT
|
||||
# This constant no longer exists in Scintilla, but I'll put it here for a while to avoid disrupting user code...
|
||||
wxSTC_CARET_CENTER = 0
|
||||
|
@@ -1819,5 +1819,5 @@ wxEVT_STC_ZOOM = stc_c.wxEVT_STC_ZOOM
|
||||
wx.wxStyledTextEventPtr = wxStyledTextEventPtr
|
||||
wx.wxStyledTextCtrlPtr = wxStyledTextCtrlPtr
|
||||
|
||||
|
||||
wxSTC_CARET_CENTER = wxSTC_CARET_STRICT
|
||||
# This constant no longer exists in Scintilla, but I'll put it here for a while to avoid disrupting user code...
|
||||
wxSTC_CARET_CENTER = 0
|
||||
|
@@ -1819,5 +1819,5 @@ wxEVT_STC_ZOOM = stc_c.wxEVT_STC_ZOOM
|
||||
wx.wxStyledTextEventPtr = wxStyledTextEventPtr
|
||||
wx.wxStyledTextCtrlPtr = wxStyledTextCtrlPtr
|
||||
|
||||
|
||||
wxSTC_CARET_CENTER = wxSTC_CARET_STRICT
|
||||
# This constant no longer exists in Scintilla, but I'll put it here for a while to avoid disrupting user code...
|
||||
wxSTC_CARET_CENTER = 0
|
||||
|
@@ -45,7 +45,10 @@ class CustomDataTable(wxPyGridTableBase):
|
||||
return len(self.data[0])
|
||||
|
||||
def IsEmptyCell(self, row, col):
|
||||
return not self.data[row][col]
|
||||
try:
|
||||
return not self.data[row][col]
|
||||
except IndexError:
|
||||
return true
|
||||
|
||||
# Get/Set values in the table. The Python version of these
|
||||
# methods can handle any data-type, (as long as the Editor and
|
||||
@@ -138,8 +141,22 @@ class CustTableGrid(wxGrid):
|
||||
class TestFrame(wxFrame):
|
||||
def __init__(self, parent, log):
|
||||
wxFrame.__init__(self, parent, -1, "Custom Table, data driven Grid Demo", size=(640,480))
|
||||
grid = CustTableGrid(self, log)
|
||||
p = wxPanel(self, -1, style=0)
|
||||
grid = CustTableGrid(p, log)
|
||||
b = wxButton(p, -1, "Another Control...")
|
||||
b.SetDefault()
|
||||
EVT_BUTTON(self, b.GetId(), self.OnButton)
|
||||
EVT_SET_FOCUS(b, self.OnButtonFocus)
|
||||
bs = wxBoxSizer(wxVERTICAL)
|
||||
bs.Add(grid, 1, wxGROW|wxALL, 5)
|
||||
bs.Add(b)
|
||||
p.SetSizer(bs)
|
||||
|
||||
def OnButton(self, evt):
|
||||
print "button selected"
|
||||
|
||||
def OnButtonFocus(self, evt):
|
||||
print "button focus"
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
@@ -37,6 +37,7 @@ _treeList = [
|
||||
'wxKeyEvents',
|
||||
'wxWizard',
|
||||
'wxXmlResourceHandler',
|
||||
'wxTimeCtrl',
|
||||
]),
|
||||
|
||||
# managed windows == things with a caption you can close
|
||||
@@ -129,6 +130,7 @@ _treeList = [
|
||||
'wxRightTextCtrl',
|
||||
'wxStyledTextCtrl_1',
|
||||
'wxStyledTextCtrl_2',
|
||||
'wxTimeCtrl',
|
||||
]),
|
||||
|
||||
# How to lay out the controls in a frame/dialog
|
||||
|
@@ -223,7 +223,8 @@ class TestListCtrlPanel(wxPanel, wxColumnSorterMixin):
|
||||
|
||||
def OnItemActivated(self, event):
|
||||
self.currentItem = event.m_itemIndex
|
||||
self.log.WriteText("OnItemActivated: %s\n" % self.list.GetItemText(self.currentItem))
|
||||
self.log.WriteText("OnItemActivated: %s\nTopItem: %s" %
|
||||
(self.list.GetItemText(self.currentItem), self.list.GetTopItem()))
|
||||
|
||||
def OnItemDelete(self, event):
|
||||
self.log.WriteText("OnItemDelete\n")
|
||||
|
@@ -45,7 +45,8 @@ class TestVirtualList(wxListCtrl):
|
||||
|
||||
def OnItemActivated(self, event):
|
||||
self.currentItem = event.m_itemIndex
|
||||
self.log.WriteText("OnItemActivated: %s\n" % self.GetItemText(self.currentItem))
|
||||
self.log.WriteText("OnItemActivated: %s\nTopItem: %s\n" %
|
||||
(self.GetItemText(self.currentItem), self.GetTopItem()))
|
||||
|
||||
def getColumnText(self, index, col):
|
||||
item = self.GetItem(index, col)
|
||||
|
@@ -149,6 +149,7 @@ class MyCanvas(wxScrolledWindow):
|
||||
|
||||
def OnLeftButtonEvent(self, event):
|
||||
if event.LeftDown():
|
||||
self.SetFocus()
|
||||
self.SetXY(event)
|
||||
self.curLine = []
|
||||
self.CaptureMouse()
|
||||
|
@@ -22,6 +22,7 @@ class TestPanel(wxPanel):
|
||||
l1 = wxStaticText(self, -1, "wxTextCtrl")
|
||||
t1 = wxTextCtrl(self, 10, "Test it out and see", size=(125, -1))
|
||||
t1.SetInsertionPoint(0)
|
||||
self.tc1 = t1
|
||||
EVT_TEXT(self, 10, self.EvtText)
|
||||
EVT_CHAR(t1, self.EvtChar)
|
||||
EVT_SET_FOCUS(t1, self.OnSetFocus)
|
||||
@@ -43,6 +44,8 @@ class TestPanel(wxPanel):
|
||||
EVT_BUTTON(self, b.GetId(), self.OnTestReplace)
|
||||
b2 = wxButton(self, -1, "Test GetSelection")
|
||||
EVT_BUTTON(self, b2.GetId(), self.OnTestGetSelection)
|
||||
b3 = wxButton(self, -1, "Test WriteText")
|
||||
EVT_BUTTON(self, b3.GetId(), self.OnTestWriteText)
|
||||
self.tc = t3
|
||||
|
||||
l4 = wxStaticText(self, -1, "Rich Text")
|
||||
@@ -58,6 +61,7 @@ class TestPanel(wxPanel):
|
||||
bsizer = wxBoxSizer(wxVERTICAL)
|
||||
bsizer.Add(b, 0, wxGROW)
|
||||
bsizer.Add(b2, 0, wxGROW)
|
||||
bsizer.Add(b3, 0, wxGROW)
|
||||
|
||||
sizer = wxFlexGridSizer(cols=3, hgap=6, vgap=6)
|
||||
sizer.AddMany([ l1, t1, (0,0),
|
||||
@@ -84,6 +88,9 @@ class TestPanel(wxPanel):
|
||||
self.tc.Replace(5, 9, "IS A")
|
||||
#self.tc.Remove(5, 9)
|
||||
|
||||
def OnTestWriteText(self, evt):
|
||||
self.tc.WriteText("TEXT")
|
||||
|
||||
def OnTestGetSelection(self, evt):
|
||||
start, end = self.tc.GetSelection()
|
||||
text = self.tc.GetValue()
|
||||
|
117
wxPython/demo/wxTimeCtrl.py
Normal file
117
wxPython/demo/wxTimeCtrl.py
Normal file
@@ -0,0 +1,117 @@
|
||||
from wxPython.wx import *
|
||||
from wxPython.lib.timectrl import *
|
||||
|
||||
import string
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class TestPanel(wxPanel):
|
||||
def __init__(self, parent, log):
|
||||
wxPanel.__init__(self, parent, -1)
|
||||
self.log = log
|
||||
panel = wxPanel(self, -1)
|
||||
grid = wxFlexGridSizer( 0, 2, 20, 0 )
|
||||
|
||||
text1 = wxStaticText( panel, 10, "A 12-hour format wxTimeCtrl:", wxDefaultPosition, wxDefaultSize, 0 )
|
||||
grid.AddWindow( text1, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
hsizer1 = wxBoxSizer( wxHORIZONTAL )
|
||||
self.time12 = wxTimeCtrl(panel, 20, name="12 hour time")
|
||||
hsizer1.AddWindow( self.time12, 0, wxALIGN_CENTRE, 5 )
|
||||
spin1 = wxSpinButton( panel, 30, wxDefaultPosition, wxSize(-1,20), 0 )
|
||||
self.time12.BindSpinButton(spin1)
|
||||
hsizer1.AddWindow( spin1, 0, wxALIGN_CENTRE, 5 )
|
||||
grid.AddSizer( hsizer1, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 )
|
||||
|
||||
text2 = wxStaticText( panel, 40, "A 24-hour format wxTimeCtrl:", wxDefaultPosition, wxDefaultSize, 0 )
|
||||
grid.AddWindow( text2, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP|wxBOTTOM, 5 )
|
||||
|
||||
hsizer2 = wxBoxSizer( wxHORIZONTAL )
|
||||
self.time24 = wxTimeCtrl(panel, 50, fmt24hr=true, name="24 hour time")
|
||||
hsizer2.AddWindow( self.time24, 0, wxALIGN_CENTRE, 5 )
|
||||
spin2 = wxSpinButton( panel, 60, wxDefaultPosition, wxSize(-1,20), 0 )
|
||||
self.time24.BindSpinButton(spin2)
|
||||
hsizer2.AddWindow( spin2, 0, wxALIGN_CENTRE, 5 )
|
||||
grid.AddSizer( hsizer2, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 )
|
||||
|
||||
panel.SetAutoLayout(true)
|
||||
panel.SetSizer(grid)
|
||||
grid.Fit(panel)
|
||||
panel.Move((50,50))
|
||||
self.panel = panel
|
||||
|
||||
EVT_TIMEUPDATE(self, self.time12.GetId(), self.OnTimeChange)
|
||||
EVT_TIMEUPDATE(self, self.time24.GetId(), self.OnTimeChange)
|
||||
|
||||
|
||||
def OnTimeChange(self, event):
|
||||
timectrl = self.panel.FindWindowById(event.GetId())
|
||||
self.log.write('%s = %s\n' % (
|
||||
timectrl.GetName(), timectrl.GetValue() ) )
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
def runTest(frame, nb, log):
|
||||
win = TestPanel(nb, log)
|
||||
return win
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# It's nice to be able to use HTML here, but line breaks in the triple quoted string
|
||||
# cause the resulting output to look funny, as they seem to be interpreted by the
|
||||
# parser...
|
||||
|
||||
overview = """<html><body>
|
||||
<P>
|
||||
<B>wxTimeCtrl</B> provides a multi-cell control that allows manipulation of a time value. It supports 12 or 24 hour format, and you can use wxDateTime or mxDateTimet o get/set values from the control.
|
||||
<P>
|
||||
Left/right/tab keys to switch cells within a wxTimeCtrl, and the up/down arrows act like a spin control. wxTimeCtrl also allows for an actual spin button to be attached to the control, so that it acts like the up/down arrow keys.
|
||||
<P>
|
||||
Here's the interface for wxTimeCtrl:
|
||||
<DL>
|
||||
|
||||
<PRE>
|
||||
<B>wxTimeCtrl</B>(parent, id = -1,
|
||||
<B>value</B> = '12:00:00 AM',
|
||||
pos = wxDefaultPosition,
|
||||
size = wxDefaultSize,
|
||||
<B>fmt24hr</B> = false,
|
||||
<B>spinButton</B> = None,
|
||||
<B>style</B> = wxTE_PROCESS_TAB,
|
||||
name = "time")
|
||||
</PRE>
|
||||
<UL>
|
||||
<DT><B>value</B><DD>If no initial value is set, the default will be midnight; if an illegal string is specified, a ValueError will result. (You can always later set the initial time with SetValue() after instantiation of the control.)
|
||||
<DL><B>size</B><DD>The size of the control will be automatically adjusted for 12/24 hour format if wxDefaultSize is specified.
|
||||
<DT><B>fmt24hr</B><DD>If true, control will display time in 24 hour time format; if false, it will use 12 hour AM/PM format. SetValue() will adjust values accordingly for the control, based on the format specified.
|
||||
<DT><B>spinButton</B><DD>If specified, this button's events will be bound to the behavior of the wxTimeCtrl, working like up/down cursor key events. (See BindSpinButton.)
|
||||
<DT><B>style</B><DD>By default, wxTimeCtrl will process TAB events, by allowing tab to the different cells within the control.
|
||||
</DL>
|
||||
</UL>
|
||||
<DT><B>SetValue(time_string)</B><DD>Sets the value of the control to a particular time, given a valid time string; raises ValueError on invalid value
|
||||
<DT><B>GetValue()</B><DD>Retrieves the string value of the time from the control
|
||||
<BR>
|
||||
<DT><B>SetWxDateTime(wxDateTime)</B><DD>Uses the time portion of a wxDateTime to construct a value for the control.
|
||||
<DT><B>GetWxDateTime()</B><DD>Retrieves the value of the control, and applies it to the wxDateTimeFromHMS() constructor, and returns the resulting value. (This returns the date portion as "today".)
|
||||
<BR>
|
||||
<DT><B>SetMxDateTime(mxDateTime)</B><DD>Uses the time portion of an mxDateTime to construct a value for the control. <EM>NOTE:</EM> This imports mx.DateTime at runtime only if this or the Get function is called.
|
||||
<DT><B>GetMxDateTime()</B><DD>Retrieves the value of the control and applies it to the DateTime.Time() constructor, and returns the resulting value. (mxDateTime is smart enough to know this is just a time value.)
|
||||
<BR>
|
||||
<DT><B>BindSpinButton(wxSpinBtton)</B><DD>Binds an externally created spin button to the control, so that up/down spin events change the active cell or selection in the control (in addition to the up/down cursor keys.) (This is primarily to allow you to create a "standard" interface to time controls, as seen in Windows.)
|
||||
<BR>
|
||||
<DT><B>EVT_TIMEUPDATE(win, id, func)</B><DD>func is fired whenever the value of the control changes.
|
||||
</DL>
|
||||
</body></html>
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys,os
|
||||
import run
|
||||
run.main(['', os.path.basename(sys.argv[0])])
|
||||
|
||||
|
||||
|
83
wxPython/distrib/README.1st.txt
Normal file
83
wxPython/distrib/README.1st.txt
Normal file
@@ -0,0 +1,83 @@
|
||||
README for wxPythonSrc-*.tar.gz
|
||||
-------------------------------
|
||||
|
||||
Prior to version 2.3.3 of wxPython I had always made my Linux/Unix
|
||||
binaries based on the released binary of wxGTK and wxGTK-gl. This
|
||||
imposed a few restrictions and so starting with 2.3.3 I have decided
|
||||
to do a combined binary that inlcudes wxGTK as well as wxPython. This
|
||||
allows me a bit more flexibility and is consistent with how the
|
||||
Windows and Mac OS X binaries are built.
|
||||
|
||||
If you are reading this file then you are probably interested in
|
||||
building your own copy of wxPython from the sources contained in this
|
||||
file. If you wish to use the released wxGTK binary as has been done
|
||||
in the past then you can still follow the old build directions in
|
||||
wxPython/BUILD.unix.txt. If you are building for Windows or Mac OS X
|
||||
then you should look at BUILD.win32.txt or BUILD.osx.txt respectivly.
|
||||
In all these cases you should use the IN_CVS_TREE=1 flag since this
|
||||
archive is really just a modified CVS snapshot.
|
||||
|
||||
If, on the other hand, you would like to build Linux/Unix binaries
|
||||
with a private copy of wxGTK like what I am now distributing then
|
||||
you'll want to follow the instructions in this file.
|
||||
|
||||
Clear as mud? Good. Let's get started.
|
||||
|
||||
|
||||
1. We'll be making a private copy of wxGTK so it doesn't conflict with
|
||||
one used by wxGTK C++ apps that expect to have the default binary
|
||||
installed from RPM or whatever. I put it in /usr/lib/wxPython, but
|
||||
you can use whatever you like. I'll just set a variable to our wx
|
||||
prefix to reference later:
|
||||
|
||||
export WXPREF=/usr/lib/wxPython
|
||||
|
||||
|
||||
2. Make a build directory and configure wxGTK.
|
||||
|
||||
cd wxPythonGTK-2.3.3 # or whatever the top-level dir is
|
||||
mkdir build
|
||||
cd build
|
||||
../configure --with-gtk \
|
||||
--prefix=$WXPREF \
|
||||
--enable-rpath=$WXPREF/lib \
|
||||
--with-opengl \
|
||||
--enable-optimise \
|
||||
--enable-debug_flag \
|
||||
-with-libjpeg=builtin \
|
||||
--with-libpng=builtin \
|
||||
--with-libtiff=builtin \
|
||||
--with-zlib=builtin
|
||||
|
||||
You may want to use --enable-debug instead of --enable-optimise if
|
||||
you need to run though a debugger and want full debugging symbols.
|
||||
|
||||
|
||||
3. Build and install wxGTK. (You may need to be root for the last
|
||||
step, depending on where your WXPREF is.)
|
||||
|
||||
make
|
||||
cd ../locale
|
||||
make allmo
|
||||
cd ../build
|
||||
make install
|
||||
|
||||
4. Build and install wxPython. If you want to use a different version
|
||||
of Python than is found by default on the PATH then specify the
|
||||
whole pathname in these steps. The version of Python that runs
|
||||
setup.py is the version wxPython will be built and installed for.
|
||||
(You will need to be root for the install step unless your Python
|
||||
is not in a system location.)
|
||||
|
||||
cd ../wxPython
|
||||
python setup.py \
|
||||
IN_CVS_TREE=1 WX_CONFIG=$WXPREF/bin/wx-config \
|
||||
build install
|
||||
|
||||
5. That's all!
|
||||
|
||||
--
|
||||
Robin Dunn
|
||||
Software Craftsman
|
||||
http://wxPython.org Java give you jitters? Relax with wxPython!
|
||||
|
@@ -172,6 +172,7 @@ cp ${distdir}/wxPython${port}.spec ${builddir}/${tarver}/wxPython${port}.spec
|
||||
|
||||
if [ -z "${skiptar}" ]; then
|
||||
echo "*** Creating tarball..."
|
||||
cp distrib/README.1st.txt ${builddir}/${tarver}
|
||||
pushd ${builddir} > /dev/null
|
||||
tar cvf ${distdir}/${tarver}.tar ${tarver} > /dev/null
|
||||
echo "*** Compressing..."
|
||||
|
@@ -13,7 +13,7 @@ from my_distutils import run_swig, contrib_copy_tree
|
||||
# flags and values that affect this script
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
VERSION = "2.3.3pre8"
|
||||
VERSION = "2.3.3.1"
|
||||
DESCRIPTION = "Cross platform GUI toolkit for Python"
|
||||
AUTHOR = "Robin Dunn"
|
||||
AUTHOR_EMAIL = "Robin Dunn <robin@alldunn.com>"
|
||||
|
@@ -1 +1 @@
|
||||
ver = '2.3.3pre8'
|
||||
ver = '2.3.3.1'
|
||||
|
@@ -765,10 +765,14 @@ class wxApp(wxPyApp):
|
||||
error = 'wxApp.error'
|
||||
outputWindowClass = wxPyOnDemandOutputWindow
|
||||
|
||||
def __init__(self, redirect=_defRedirect, filename=None):
|
||||
def __init__(self, redirect=_defRedirect, filename=None, useBestVisual=true):
|
||||
wxPyApp.__init__(self)
|
||||
self.stdioWin = None
|
||||
self.saveStdio = (sys.stdout, sys.stderr)
|
||||
|
||||
# This has to be done before OnInit
|
||||
self.SetUseBestVisual(useBestVisual)
|
||||
|
||||
if redirect:
|
||||
self.RedirectStdio(filename)
|
||||
# this initializes wxWindows and then calls our OnInit
|
||||
|
@@ -9978,6 +9978,35 @@ static PyObject *_wrap_wxMenuBar_EnableTop(PyObject *self, PyObject *args, PyObj
|
||||
return _resultobj;
|
||||
}
|
||||
|
||||
#define wxMenuBar_IsEnabledTop(_swigobj,_swigarg0) (_swigobj->IsEnabledTop(_swigarg0))
|
||||
static PyObject *_wrap_wxMenuBar_IsEnabledTop(PyObject *self, PyObject *args, PyObject *kwargs) {
|
||||
PyObject * _resultobj;
|
||||
bool _result;
|
||||
wxMenuBar * _arg0;
|
||||
size_t _arg1;
|
||||
PyObject * _argo0 = 0;
|
||||
char *_kwnames[] = { "self","pos", NULL };
|
||||
|
||||
self = self;
|
||||
if(!PyArg_ParseTupleAndKeywords(args,kwargs,"Oi:wxMenuBar_IsEnabledTop",_kwnames,&_argo0,&_arg1))
|
||||
return NULL;
|
||||
if (_argo0) {
|
||||
if (_argo0 == Py_None) { _arg0 = NULL; }
|
||||
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_wxMenuBar_p")) {
|
||||
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of wxMenuBar_IsEnabledTop. Expected _wxMenuBar_p.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
{
|
||||
PyThreadState* __tstate = wxPyBeginAllowThreads();
|
||||
_result = (bool )wxMenuBar_IsEnabledTop(_arg0,_arg1);
|
||||
|
||||
wxPyEndAllowThreads(__tstate);
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
} _resultobj = Py_BuildValue("i",_result);
|
||||
return _resultobj;
|
||||
}
|
||||
|
||||
#define wxMenuBar_SetLabelTop(_swigobj,_swigarg0,_swigarg1) (_swigobj->SetLabelTop(_swigarg0,_swigarg1))
|
||||
static PyObject *_wrap_wxMenuBar_SetLabelTop(PyObject *self, PyObject *args, PyObject *kwargs) {
|
||||
PyObject * _resultobj;
|
||||
@@ -11377,6 +11406,7 @@ static PyMethodDef windowscMethods[] = {
|
||||
{ "wxMenuBar_FindMenu", (PyCFunction) _wrap_wxMenuBar_FindMenu, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_GetLabelTop", (PyCFunction) _wrap_wxMenuBar_GetLabelTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_SetLabelTop", (PyCFunction) _wrap_wxMenuBar_SetLabelTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_IsEnabledTop", (PyCFunction) _wrap_wxMenuBar_IsEnabledTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_EnableTop", (PyCFunction) _wrap_wxMenuBar_EnableTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_Remove", (PyCFunction) _wrap_wxMenuBar_Remove, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_Replace", (PyCFunction) _wrap_wxMenuBar_Replace, METH_VARARGS | METH_KEYWORDS },
|
||||
|
@@ -977,6 +977,9 @@ class wxMenuBarPtr(wxWindowPtr):
|
||||
def EnableTop(self, *_args, **_kwargs):
|
||||
val = apply(windowsc.wxMenuBar_EnableTop,(self,) + _args, _kwargs)
|
||||
return val
|
||||
def IsEnabledTop(self, *_args, **_kwargs):
|
||||
val = apply(windowsc.wxMenuBar_IsEnabledTop,(self,) + _args, _kwargs)
|
||||
return val
|
||||
def SetLabelTop(self, *_args, **_kwargs):
|
||||
val = apply(windowsc.wxMenuBar_SetLabelTop,(self,) + _args, _kwargs)
|
||||
return val
|
||||
|
@@ -1691,10 +1691,14 @@ class wxApp(wxPyApp):
|
||||
error = 'wxApp.error'
|
||||
outputWindowClass = wxPyOnDemandOutputWindow
|
||||
|
||||
def __init__(self, redirect=_defRedirect, filename=None):
|
||||
def __init__(self, redirect=_defRedirect, filename=None, useBestVisual=true):
|
||||
wxPyApp.__init__(self)
|
||||
self.stdioWin = None
|
||||
self.saveStdio = (sys.stdout, sys.stderr)
|
||||
|
||||
# This has to be done before OnInit
|
||||
self.SetUseBestVisual(useBestVisual)
|
||||
|
||||
if redirect:
|
||||
self.RedirectStdio(filename)
|
||||
# this initializes wxWindows and then calls our OnInit
|
||||
|
@@ -92,7 +92,6 @@ BOOL WINAPI DllMain(
|
||||
|
||||
|
||||
wxPyApp::wxPyApp() {
|
||||
SetUseBestVisual(TRUE);
|
||||
}
|
||||
|
||||
wxPyApp::~wxPyApp() {
|
||||
@@ -889,7 +888,6 @@ size_t wxPyCBInputStream::OnSysRead(void *buffer, size_t bufsize) {
|
||||
else
|
||||
m_lasterror = wxSTREAM_READ_ERROR;
|
||||
wxPyEndBlockThreads();
|
||||
m_lastcount = o;
|
||||
return o;
|
||||
}
|
||||
|
||||
|
@@ -9978,6 +9978,35 @@ static PyObject *_wrap_wxMenuBar_EnableTop(PyObject *self, PyObject *args, PyObj
|
||||
return _resultobj;
|
||||
}
|
||||
|
||||
#define wxMenuBar_IsEnabledTop(_swigobj,_swigarg0) (_swigobj->IsEnabledTop(_swigarg0))
|
||||
static PyObject *_wrap_wxMenuBar_IsEnabledTop(PyObject *self, PyObject *args, PyObject *kwargs) {
|
||||
PyObject * _resultobj;
|
||||
bool _result;
|
||||
wxMenuBar * _arg0;
|
||||
size_t _arg1;
|
||||
PyObject * _argo0 = 0;
|
||||
char *_kwnames[] = { "self","pos", NULL };
|
||||
|
||||
self = self;
|
||||
if(!PyArg_ParseTupleAndKeywords(args,kwargs,"Oi:wxMenuBar_IsEnabledTop",_kwnames,&_argo0,&_arg1))
|
||||
return NULL;
|
||||
if (_argo0) {
|
||||
if (_argo0 == Py_None) { _arg0 = NULL; }
|
||||
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_wxMenuBar_p")) {
|
||||
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of wxMenuBar_IsEnabledTop. Expected _wxMenuBar_p.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
{
|
||||
PyThreadState* __tstate = wxPyBeginAllowThreads();
|
||||
_result = (bool )wxMenuBar_IsEnabledTop(_arg0,_arg1);
|
||||
|
||||
wxPyEndAllowThreads(__tstate);
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
} _resultobj = Py_BuildValue("i",_result);
|
||||
return _resultobj;
|
||||
}
|
||||
|
||||
#define wxMenuBar_SetLabelTop(_swigobj,_swigarg0,_swigarg1) (_swigobj->SetLabelTop(_swigarg0,_swigarg1))
|
||||
static PyObject *_wrap_wxMenuBar_SetLabelTop(PyObject *self, PyObject *args, PyObject *kwargs) {
|
||||
PyObject * _resultobj;
|
||||
@@ -11377,6 +11406,7 @@ static PyMethodDef windowscMethods[] = {
|
||||
{ "wxMenuBar_FindMenu", (PyCFunction) _wrap_wxMenuBar_FindMenu, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_GetLabelTop", (PyCFunction) _wrap_wxMenuBar_GetLabelTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_SetLabelTop", (PyCFunction) _wrap_wxMenuBar_SetLabelTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_IsEnabledTop", (PyCFunction) _wrap_wxMenuBar_IsEnabledTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_EnableTop", (PyCFunction) _wrap_wxMenuBar_EnableTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_Remove", (PyCFunction) _wrap_wxMenuBar_Remove, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_Replace", (PyCFunction) _wrap_wxMenuBar_Replace, METH_VARARGS | METH_KEYWORDS },
|
||||
|
@@ -977,6 +977,9 @@ class wxMenuBarPtr(wxWindowPtr):
|
||||
def EnableTop(self, *_args, **_kwargs):
|
||||
val = apply(windowsc.wxMenuBar_EnableTop,(self,) + _args, _kwargs)
|
||||
return val
|
||||
def IsEnabledTop(self, *_args, **_kwargs):
|
||||
val = apply(windowsc.wxMenuBar_IsEnabledTop,(self,) + _args, _kwargs)
|
||||
return val
|
||||
def SetLabelTop(self, *_args, **_kwargs):
|
||||
val = apply(windowsc.wxMenuBar_SetLabelTop,(self,) + _args, _kwargs)
|
||||
return val
|
||||
|
@@ -1691,10 +1691,14 @@ class wxApp(wxPyApp):
|
||||
error = 'wxApp.error'
|
||||
outputWindowClass = wxPyOnDemandOutputWindow
|
||||
|
||||
def __init__(self, redirect=_defRedirect, filename=None):
|
||||
def __init__(self, redirect=_defRedirect, filename=None, useBestVisual=true):
|
||||
wxPyApp.__init__(self)
|
||||
self.stdioWin = None
|
||||
self.saveStdio = (sys.stdout, sys.stderr)
|
||||
|
||||
# This has to be done before OnInit
|
||||
self.SetUseBestVisual(useBestVisual)
|
||||
|
||||
if redirect:
|
||||
self.RedirectStdio(filename)
|
||||
# this initializes wxWindows and then calls our OnInit
|
||||
|
@@ -10072,6 +10072,35 @@ static PyObject *_wrap_wxMenuBar_EnableTop(PyObject *self, PyObject *args, PyObj
|
||||
return _resultobj;
|
||||
}
|
||||
|
||||
#define wxMenuBar_IsEnabledTop(_swigobj,_swigarg0) (_swigobj->IsEnabledTop(_swigarg0))
|
||||
static PyObject *_wrap_wxMenuBar_IsEnabledTop(PyObject *self, PyObject *args, PyObject *kwargs) {
|
||||
PyObject * _resultobj;
|
||||
bool _result;
|
||||
wxMenuBar * _arg0;
|
||||
size_t _arg1;
|
||||
PyObject * _argo0 = 0;
|
||||
char *_kwnames[] = { "self","pos", NULL };
|
||||
|
||||
self = self;
|
||||
if(!PyArg_ParseTupleAndKeywords(args,kwargs,"Oi:wxMenuBar_IsEnabledTop",_kwnames,&_argo0,&_arg1))
|
||||
return NULL;
|
||||
if (_argo0) {
|
||||
if (_argo0 == Py_None) { _arg0 = NULL; }
|
||||
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_wxMenuBar_p")) {
|
||||
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of wxMenuBar_IsEnabledTop. Expected _wxMenuBar_p.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
{
|
||||
PyThreadState* __tstate = wxPyBeginAllowThreads();
|
||||
_result = (bool )wxMenuBar_IsEnabledTop(_arg0,_arg1);
|
||||
|
||||
wxPyEndAllowThreads(__tstate);
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
} _resultobj = Py_BuildValue("i",_result);
|
||||
return _resultobj;
|
||||
}
|
||||
|
||||
#define wxMenuBar_SetLabelTop(_swigobj,_swigarg0,_swigarg1) (_swigobj->SetLabelTop(_swigarg0,_swigarg1))
|
||||
static PyObject *_wrap_wxMenuBar_SetLabelTop(PyObject *self, PyObject *args, PyObject *kwargs) {
|
||||
PyObject * _resultobj;
|
||||
@@ -11859,6 +11888,7 @@ static PyMethodDef windowscMethods[] = {
|
||||
{ "wxMenuBar_FindMenu", (PyCFunction) _wrap_wxMenuBar_FindMenu, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_GetLabelTop", (PyCFunction) _wrap_wxMenuBar_GetLabelTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_SetLabelTop", (PyCFunction) _wrap_wxMenuBar_SetLabelTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_IsEnabledTop", (PyCFunction) _wrap_wxMenuBar_IsEnabledTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_EnableTop", (PyCFunction) _wrap_wxMenuBar_EnableTop, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_Remove", (PyCFunction) _wrap_wxMenuBar_Remove, METH_VARARGS | METH_KEYWORDS },
|
||||
{ "wxMenuBar_Replace", (PyCFunction) _wrap_wxMenuBar_Replace, METH_VARARGS | METH_KEYWORDS },
|
||||
|
@@ -983,6 +983,9 @@ class wxMenuBarPtr(wxWindowPtr):
|
||||
def EnableTop(self, *_args, **_kwargs):
|
||||
val = apply(windowsc.wxMenuBar_EnableTop,(self,) + _args, _kwargs)
|
||||
return val
|
||||
def IsEnabledTop(self, *_args, **_kwargs):
|
||||
val = apply(windowsc.wxMenuBar_IsEnabledTop,(self,) + _args, _kwargs)
|
||||
return val
|
||||
def SetLabelTop(self, *_args, **_kwargs):
|
||||
val = apply(windowsc.wxMenuBar_SetLabelTop,(self,) + _args, _kwargs)
|
||||
return val
|
||||
|
@@ -1697,10 +1697,14 @@ class wxApp(wxPyApp):
|
||||
error = 'wxApp.error'
|
||||
outputWindowClass = wxPyOnDemandOutputWindow
|
||||
|
||||
def __init__(self, redirect=_defRedirect, filename=None):
|
||||
def __init__(self, redirect=_defRedirect, filename=None, useBestVisual=true):
|
||||
wxPyApp.__init__(self)
|
||||
self.stdioWin = None
|
||||
self.saveStdio = (sys.stdout, sys.stderr)
|
||||
|
||||
# This has to be done before OnInit
|
||||
self.SetUseBestVisual(useBestVisual)
|
||||
|
||||
if redirect:
|
||||
self.RedirectStdio(filename)
|
||||
# this initializes wxWindows and then calls our OnInit
|
||||
|
@@ -761,6 +761,7 @@ public:
|
||||
wxMenu *Replace(size_t pos, wxMenu *menu, const wxString& title);
|
||||
wxMenu *Remove(size_t pos);
|
||||
void EnableTop(size_t pos, bool enable);
|
||||
bool IsEnabledTop(size_t pos);
|
||||
void SetLabelTop(size_t pos, const wxString& label);
|
||||
wxString GetLabelTop(size_t pos);
|
||||
int FindMenu(const wxString& title);
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
"""PyCrustApp is a python shell and namespace browser application."""
|
||||
|
||||
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
"""PyFillingApp is a python namespace inspection application."""
|
||||
|
||||
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
"""PyShellApp is a python shell application."""
|
||||
|
||||
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
|
||||
|
@@ -132,137 +132,102 @@ class wxColumnSorterMixin:
|
||||
|
||||
class wxListCtrlAutoWidthMixin:
|
||||
""" A mix-in class that automatically resizes the last column to take up
|
||||
the remaining width of the wxListCtrl.
|
||||
the remaining width of the wxListCtrl.
|
||||
|
||||
This causes the wxListCtrl to automatically take up the full width of
|
||||
the list, without either a horizontal scroll bar (unless absolutely
|
||||
necessary) or empty space to the right of the last column.
|
||||
This causes the wxListCtrl to automatically take up the full width of
|
||||
the list, without either a horizontal scroll bar (unless absolutely
|
||||
necessary) or empty space to the right of the last column.
|
||||
|
||||
NOTE: This only works for report-style lists.
|
||||
NOTE: This only works for report-style lists.
|
||||
|
||||
WARNING: If you override the EVT_SIZE event in your wxListCtrl, make
|
||||
sure you call event.Skip() to ensure that the mixin's
|
||||
_OnResize method is called.
|
||||
WARNING: If you override the EVT_SIZE event in your wxListCtrl, make
|
||||
sure you call event.Skip() to ensure that the mixin's
|
||||
_OnResize method is called.
|
||||
|
||||
This mix-in class was written by Erik Westra <ewestra@wave.co.nz>
|
||||
This mix-in class was written by Erik Westra <ewestra@wave.co.nz>
|
||||
"""
|
||||
def __init__(self):
|
||||
""" Standard initialiser.
|
||||
"""
|
||||
self._needResize = false
|
||||
self._lastColMinWidth = None
|
||||
""" Standard initialiser.
|
||||
"""
|
||||
self._lastColMinWidth = None
|
||||
|
||||
EVT_SIZE(self, self._onResize)
|
||||
EVT_LIST_COL_END_DRAG(self, self.GetId(), self._onEndColDrag)
|
||||
EVT_IDLE(self, self._onIdle)
|
||||
EVT_SIZE(self, self._onResize)
|
||||
EVT_LIST_COL_END_DRAG(self, self.GetId(), self._onResize)
|
||||
|
||||
|
||||
def resizeLastColumn(self, minWidth):
|
||||
""" Resize the last column appropriately.
|
||||
""" Resize the last column appropriately.
|
||||
|
||||
If the list's columns are too wide to fit within the window, we use
|
||||
a horizontal scrollbar. Otherwise, we expand the right-most column
|
||||
to take up the remaining free space in the list.
|
||||
If the list's columns are too wide to fit within the window, we use
|
||||
a horizontal scrollbar. Otherwise, we expand the right-most column
|
||||
to take up the remaining free space in the list.
|
||||
|
||||
This method is called automatically when the wxListCtrl is resized;
|
||||
you can also call it yourself whenever you want the last column to
|
||||
be resized appropriately (eg, when adding, removing or resizing
|
||||
columns).
|
||||
This method is called automatically when the wxListCtrl is resized;
|
||||
you can also call it yourself whenever you want the last column to
|
||||
be resized appropriately (eg, when adding, removing or resizing
|
||||
columns).
|
||||
|
||||
'minWidth' is the preferred minimum width for the last column.
|
||||
"""
|
||||
self._lastColMinWidth = minWidth
|
||||
self._doResize()
|
||||
'minWidth' is the preferred minimum width for the last column.
|
||||
"""
|
||||
self._lastColMinWidth = minWidth
|
||||
self._doResize()
|
||||
|
||||
# =====================
|
||||
# == Private Methods ==
|
||||
# =====================
|
||||
|
||||
def _onResize(self, event):
|
||||
""" Respond to the wxListCtrl being resized.
|
||||
""" Respond to the wxListCtrl being resized.
|
||||
|
||||
We automatically resize the last column in the list.
|
||||
"""
|
||||
self._doResize()
|
||||
event.Skip()
|
||||
|
||||
def _onEndColDrag(self, event):
|
||||
""" Respond to the user resizing one of our columns.
|
||||
|
||||
We resize the last column in the list to match. Note that, because
|
||||
of a quirk in the way columns are resized under MS Windows, we
|
||||
actually have to do the column resize in idle time.
|
||||
"""
|
||||
self._needResize = true
|
||||
event.Skip()
|
||||
|
||||
|
||||
def _onIdle(self, event):
|
||||
""" Respond to an idle event.
|
||||
|
||||
We resize the last column, if we've been asked to do so.
|
||||
"""
|
||||
if self._needResize:
|
||||
self._doResize()
|
||||
self.Refresh() # Fixes redraw problem under MS Windows.
|
||||
self._needResize = false
|
||||
We automatically resize the last column in the list.
|
||||
"""
|
||||
wxCallAfter(self._doResize)
|
||||
event.Skip()
|
||||
|
||||
|
||||
def _doResize(self):
|
||||
""" Resize the last column as appropriate.
|
||||
""" Resize the last column as appropriate.
|
||||
|
||||
If the list's columns are too wide to fit within the window, we use
|
||||
a horizontal scrollbar. Otherwise, we expand the right-most column
|
||||
to take up the remaining free space in the list.
|
||||
If the list's columns are too wide to fit within the window, we use
|
||||
a horizontal scrollbar. Otherwise, we expand the right-most column
|
||||
to take up the remaining free space in the list.
|
||||
|
||||
We remember the current size of the last column, before resizing,
|
||||
as the preferred minimum width if we haven't previously been given
|
||||
or calculated a minimum width. This ensure that repeated calls to
|
||||
_doResize() don't cause the last column to size itself too large.
|
||||
"""
|
||||
numCols = self.GetColumnCount()
|
||||
if numCols == 0: return # Nothing to resize.
|
||||
We remember the current size of the last column, before resizing,
|
||||
as the preferred minimum width if we haven't previously been given
|
||||
or calculated a minimum width. This ensure that repeated calls to
|
||||
_doResize() don't cause the last column to size itself too large.
|
||||
"""
|
||||
numCols = self.GetColumnCount()
|
||||
if numCols == 0: return # Nothing to resize.
|
||||
|
||||
if self._lastColMinWidth == None:
|
||||
self._lastColMinWidth = self.GetColumnWidth(numCols - 1)
|
||||
if self._lastColMinWidth == None:
|
||||
self._lastColMinWidth = self.GetColumnWidth(numCols - 1)
|
||||
|
||||
listWidth = self.GetSize().width
|
||||
if self.GetItemCount() > self.GetCountPerPage():
|
||||
# We're showing the vertical scrollbar -> allow for scrollbar width
|
||||
scrollWidth = wxSystemSettings_GetSystemMetric(wxSYS_VSCROLL_X)
|
||||
listWidth = listWidth - scrollWidth
|
||||
# We're showing the vertical scrollbar -> allow for scrollbar width
|
||||
# NOTE: on GTK, the scrollbar is included in the client size, but on
|
||||
# Windows it is not included
|
||||
listWidth = self.GetClientSize().width
|
||||
if wxPlatform != '__WXMSW__':
|
||||
if self.GetItemCount() > self.GetCountPerPage():
|
||||
scrollWidth = wxSystemSettings_GetSystemMetric(wxSYS_VSCROLL_X)
|
||||
listWidth = listWidth - scrollWidth
|
||||
|
||||
totColWidth = 0 # Width of all columns except last one.
|
||||
for col in range(numCols-1):
|
||||
totColWidth = totColWidth + self.GetColumnWidth(col)
|
||||
totColWidth = 0 # Width of all columns except last one.
|
||||
for col in range(numCols-1):
|
||||
totColWidth = totColWidth + self.GetColumnWidth(col)
|
||||
|
||||
lastColWidth = self.GetColumnWidth(numCols - 1)
|
||||
lastColWidth = self.GetColumnWidth(numCols - 1)
|
||||
|
||||
# NOTE: This is the extra number of pixels required to make the
|
||||
# wxListCtrl size correctly, at least under Windows 2000.
|
||||
# Unfortunately, different OSs and even different versions of the
|
||||
# same OS may implement the wxListCtrl differently, so different
|
||||
# margins may be needed to get the columns resized correctly. No
|
||||
# doubt the margin could be calculated in a more intelligent
|
||||
# manner...
|
||||
if wxPlatform == '__WXMSW__':
|
||||
margin = 6
|
||||
elif wxPlatform == '__WXGTK__':
|
||||
margin = 8
|
||||
else:
|
||||
margin = 0
|
||||
if totColWidth + self._lastColMinWidth > listWidth:
|
||||
# We haven't got the width to show the last column at its minimum
|
||||
# width -> set it to its minimum width and allow the horizontal
|
||||
# scrollbar to show.
|
||||
self.SetColumnWidth(numCols-1, self._lastColMinWidth)
|
||||
return
|
||||
|
||||
if totColWidth + self._lastColMinWidth > listWidth - margin:
|
||||
# We haven't got the width to show the last column at its minimum
|
||||
# width -> set it to its minimum width and allow the horizontal
|
||||
# scrollbar to show.
|
||||
self.SetColumnWidth(numCols-1, self._lastColMinWidth)
|
||||
return
|
||||
# Resize the last column to take up the remaining available space.
|
||||
|
||||
# Resize the last column to take up the remaining available space.
|
||||
|
||||
self.SetColumnWidth(numCols-1, listWidth - totColWidth - margin)
|
||||
self.SetColumnWidth(numCols-1, listWidth - totColWidth)
|
||||
|
||||
|
||||
|
||||
|
389
wxPython/wxPython/lib/mixins/rubberband.py
Normal file
389
wxPython/wxPython/lib/mixins/rubberband.py
Normal file
@@ -0,0 +1,389 @@
|
||||
"""
|
||||
A mixin class for doing "RubberBand"-ing on a window.
|
||||
|
||||
by "Robb Shecter" <rs@onsitetech.com>
|
||||
|
||||
$Id$
|
||||
|
||||
"""
|
||||
|
||||
from wxPython.wx import *
|
||||
import Image
|
||||
|
||||
#
|
||||
# Some miscellaneous mathematical and geometrical functions
|
||||
#
|
||||
|
||||
def isNegative(aNumber):
|
||||
"""
|
||||
x < 0: 1
|
||||
else: 0
|
||||
"""
|
||||
return aNumber < 0
|
||||
|
||||
|
||||
def normalizeBox(box):
|
||||
"""
|
||||
Convert any negative measurements in the current
|
||||
box to positive, and adjust the origin.
|
||||
"""
|
||||
x, y, w, h = box
|
||||
if w < 0:
|
||||
x += (w+1)
|
||||
w *= -1
|
||||
if h < 0:
|
||||
y += (h+1)
|
||||
h *= -1
|
||||
return (x, y, w, h)
|
||||
|
||||
|
||||
def boxToExtent(box):
|
||||
"""
|
||||
Convert a box specification to an extent specification.
|
||||
I put this into a seperate function after I realized that
|
||||
I had been implementing it wrong in several places.
|
||||
"""
|
||||
b = normalizeBox(box)
|
||||
return (b[0], b[1], b[0]+b[2]-1, b[1]+b[3]-1)
|
||||
|
||||
|
||||
def pointInBox(x, y, box):
|
||||
"""
|
||||
Return true if the given point is contained in the box.
|
||||
"""
|
||||
e = boxToExtent(box)
|
||||
return x >= e[0] and x <= e[2] and y >= e[1] and y <= e[3]
|
||||
|
||||
|
||||
def pointOnBox(x, y, box, thickness=1):
|
||||
"""
|
||||
Return true if the point is on the outside edge
|
||||
of the box. The thickness defines how thick the
|
||||
edge should be. This is necessary for HCI reasons:
|
||||
For example, it's normally very difficult for a user
|
||||
to manuever the mouse onto a one pixel border.
|
||||
"""
|
||||
outerBox = box
|
||||
innerBox = (box[0]+thickness, box[1]+thickness, box[2]-(thickness*2), box[3]-(thickness*2))
|
||||
return pointInBox(x, y, outerBox) and not pointInBox(x, y, innerBox)
|
||||
|
||||
|
||||
def getCursorPosition(x, y, box, thickness=1):
|
||||
"""
|
||||
Return a position number in the range 0 .. 7 to indicate
|
||||
where on the box border the point is. The layout is:
|
||||
|
||||
0 1 2
|
||||
7 3
|
||||
6 5 4
|
||||
"""
|
||||
x0, y0, x1, y1 = boxToExtent(box)
|
||||
w, h = box[2], box[3]
|
||||
delta = thickness - 1
|
||||
p = None
|
||||
|
||||
if pointInBox(x, y, (x0, y0, thickness, thickness)):
|
||||
p = 0
|
||||
elif pointInBox(x, y, (x1-delta, y0, thickness, thickness)):
|
||||
p = 2
|
||||
elif pointInBox(x, y, (x1-delta, y1-delta, thickness, thickness)):
|
||||
p = 4
|
||||
elif pointInBox(x, y, (x0, y1-delta, thickness, thickness)):
|
||||
p = 6
|
||||
elif pointInBox(x, y, (x0+thickness, y0, w-(thickness*2), thickness)):
|
||||
p = 1
|
||||
elif pointInBox(x, y, (x1-delta, y0+thickness, thickness, h-(thickness*2))):
|
||||
p = 3
|
||||
elif pointInBox(x, y, (x0+thickness, y1-delta, w-(thickness*2), thickness)):
|
||||
p = 5
|
||||
elif pointInBox(x, y, (x0, y0+thickness, thickness, h-(thickness*2))):
|
||||
p = 7
|
||||
|
||||
return p
|
||||
|
||||
|
||||
|
||||
|
||||
class RubberBand:
|
||||
"""
|
||||
A stretchable border which is drawn on top of an
|
||||
image to define an area.
|
||||
"""
|
||||
def __init__(self, drawingSurface, aspectRatio=None):
|
||||
self.__THICKNESS = 5
|
||||
self.drawingSurface = drawingSurface
|
||||
self.aspectRatio = aspectRatio
|
||||
self.hasLetUp = 0
|
||||
self.currentlyMoving = None
|
||||
self.currentBox = None
|
||||
self.__enabled = 1
|
||||
self.__currentCursor = None
|
||||
EVT_MOUSE_EVENTS(drawingSurface, self.__handleMouseEvents)
|
||||
EVT_PAINT(drawingSurface, self.__handleOnPaint)
|
||||
|
||||
def __setEnabled(self, enabled):
|
||||
self.__enabled = enabled
|
||||
|
||||
def __isEnabled(self):
|
||||
return self.__enabled
|
||||
|
||||
def __handleOnPaint(self, event):
|
||||
#print 'paint'
|
||||
event.Skip()
|
||||
|
||||
def __isMovingCursor(self):
|
||||
"""
|
||||
Return true if the current cursor is one used to
|
||||
mean moving the rubberband.
|
||||
"""
|
||||
return self.__currentCursor == wxCURSOR_HAND
|
||||
|
||||
def __isSizingCursor(self):
|
||||
"""
|
||||
Return true if the current cursor is one of the ones
|
||||
I may use to signify sizing.
|
||||
"""
|
||||
sizingCursors = [wxCURSOR_SIZENESW,
|
||||
wxCURSOR_SIZENS,
|
||||
wxCURSOR_SIZENWSE,
|
||||
wxCURSOR_SIZEWE,
|
||||
wxCURSOR_SIZING,
|
||||
wxCURSOR_CROSS]
|
||||
try:
|
||||
sizingCursors.index(self.__currentCursor)
|
||||
return 1
|
||||
except ValueError:
|
||||
return 0
|
||||
|
||||
|
||||
def __handleMouseEvents(self, event):
|
||||
"""
|
||||
React according to the new event. This is the main
|
||||
entry point into the class. This method contains the
|
||||
logic for the class's behavior.
|
||||
"""
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
x, y = event.GetPosition()
|
||||
|
||||
# First make sure we have started a box.
|
||||
if self.currentBox == None and not event.LeftDown():
|
||||
# No box started yet. Set cursor to the initial kind.
|
||||
self.__setCursor(wxCURSOR_CROSS)
|
||||
return
|
||||
|
||||
if event.LeftDown():
|
||||
if self.currentBox == None:
|
||||
# No RB Box, so start a new one.
|
||||
self.currentBox = (x, y, 0, 0)
|
||||
self.hasLetUp = 0
|
||||
elif self.__isSizingCursor():
|
||||
# Starting a sizing operation. Change the origin.
|
||||
position = getCursorPosition(x, y, self.currentBox, thickness=self.__THICKNESS)
|
||||
self.currentBox = self.__denormalizeBox(position, self.currentBox)
|
||||
|
||||
elif event.Dragging() and event.LeftIsDown():
|
||||
# Use the cursor type to determine operation
|
||||
if self.__isMovingCursor():
|
||||
if self.currentlyMoving or pointInBox(x, y, self.currentBox):
|
||||
if not self.currentlyMoving:
|
||||
self.currentlyMoving = (x - self.currentBox[0], y - self.currentBox[1])
|
||||
self.__moveTo(x - self.currentlyMoving[0], y - self.currentlyMoving[1])
|
||||
elif self.__isSizingCursor():
|
||||
self.__resizeBox(x, y)
|
||||
|
||||
elif event.LeftUp():
|
||||
self.hasLetUp = 1
|
||||
self.currentlyMoving = None
|
||||
self.__normalizeBox()
|
||||
|
||||
elif event.Moving() and not event.Dragging():
|
||||
# Simple mouse movement event
|
||||
self.__mouseMoved(x,y)
|
||||
|
||||
def __denormalizeBox(self, position, box):
|
||||
x, y, w, h = box
|
||||
b = box
|
||||
if position == 2 or position == 3:
|
||||
b = (x, y + (h-1), w, h * -1)
|
||||
elif position == 0 or position == 1 or position == 7:
|
||||
b = (x + (w-1), y + (h-1), w * -1, h * -1)
|
||||
elif position == 6:
|
||||
b = (x + (w-1), y, w * -1, h)
|
||||
return b
|
||||
|
||||
def __resizeBox(self, x, y):
|
||||
"""
|
||||
Resize and repaint the box based on the given mouse
|
||||
coordinates.
|
||||
"""
|
||||
# Implement the correct behavior for dragging a side
|
||||
# of the box: Only change one dimension.
|
||||
if not self.aspectRatio:
|
||||
if self.__currentCursor == wxCURSOR_SIZENS:
|
||||
x = None
|
||||
elif self.__currentCursor == wxCURSOR_SIZEWE:
|
||||
y = None
|
||||
|
||||
x0,y0,w0,h0 = self.currentBox
|
||||
currentExtent = boxToExtent(self.currentBox)
|
||||
if x == None:
|
||||
if w0 < 1:
|
||||
w0 += 1
|
||||
else:
|
||||
w0 -= 1
|
||||
x = x0 + w0
|
||||
if y == None:
|
||||
if h0 < 1:
|
||||
h0 += 1
|
||||
else:
|
||||
h0 -= 1
|
||||
y = y0 + h0
|
||||
x1,y1 = x, y
|
||||
w, h = abs(x1-x0)+1, abs(y1-y0)+1
|
||||
if self.aspectRatio:
|
||||
w = max(w, int(h * self.aspectRatio))
|
||||
h = int(w / self.aspectRatio)
|
||||
w *= [1,-1][isNegative(x1-x0)]
|
||||
h *= [1,-1][isNegative(y1-y0)]
|
||||
newbox = (x0, y0, w, h)
|
||||
self.__drawAndErase(boxToDraw=normalizeBox(newbox), boxToErase=normalizeBox(self.currentBox))
|
||||
self.currentBox = (x0, y0, w, h)
|
||||
|
||||
def __normalizeBox(self):
|
||||
"""
|
||||
Convert any negative measurements in the current
|
||||
box to positive, and adjust the origin.
|
||||
"""
|
||||
self.currentBox = normalizeBox(self.currentBox)
|
||||
|
||||
def __mouseMoved(self, x, y):
|
||||
"""
|
||||
Called when the mouse moved without any buttons pressed
|
||||
or dragging being done.
|
||||
"""
|
||||
# Are we on the bounding box?
|
||||
if pointOnBox(x, y, self.currentBox, thickness=self.__THICKNESS):
|
||||
position = getCursorPosition(x, y, self.currentBox, thickness=self.__THICKNESS)
|
||||
cursor = [
|
||||
wxCURSOR_SIZENWSE,
|
||||
wxCURSOR_SIZENS,
|
||||
wxCURSOR_SIZENESW,
|
||||
wxCURSOR_SIZEWE,
|
||||
wxCURSOR_SIZENWSE,
|
||||
wxCURSOR_SIZENS,
|
||||
wxCURSOR_SIZENESW,
|
||||
wxCURSOR_SIZEWE
|
||||
] [position]
|
||||
self.__setCursor(cursor)
|
||||
elif pointInBox(x, y, self.currentBox):
|
||||
self.__setCursor(wxCURSOR_HAND)
|
||||
else:
|
||||
self.__setCursor()
|
||||
|
||||
def __setCursor(self, id=None):
|
||||
"""
|
||||
Set the mouse cursor to the given id.
|
||||
"""
|
||||
if self.__currentCursor != id: # Avoid redundant calls
|
||||
if id:
|
||||
self.drawingSurface.SetCursor(wxStockCursor(id))
|
||||
else:
|
||||
self.drawingSurface.SetCursor(wxNullCursor)
|
||||
self.__currentCursor = id
|
||||
|
||||
def __moveCenterTo(self, x, y):
|
||||
"""
|
||||
Move the rubber band so that its center is at (x,y).
|
||||
"""
|
||||
x0, y0, w, h = self.currentBox
|
||||
x2, y2 = x - (w/2), y - (h/2)
|
||||
self.__moveTo(x2, y2)
|
||||
|
||||
def __moveTo(self, x, y):
|
||||
"""
|
||||
Move the rubber band so that its origin is at (x,y).
|
||||
"""
|
||||
newbox = (x, y, self.currentBox[2], self.currentBox[3])
|
||||
self.__drawAndErase(boxToDraw=newbox, boxToErase=self.currentBox)
|
||||
self.currentBox = newbox
|
||||
|
||||
def __drawAndErase(self, boxToDraw, boxToErase=None):
|
||||
"""
|
||||
Draw one box shape and possibly erase another.
|
||||
"""
|
||||
dc = wxClientDC(self.drawingSurface)
|
||||
dc.BeginDrawing()
|
||||
dc.SetPen(wxPen(wxWHITE, 1, wxDOT))
|
||||
dc.SetBrush(wxTRANSPARENT_BRUSH)
|
||||
dc.SetLogicalFunction(wxXOR)
|
||||
if boxToErase:
|
||||
dc.DrawRectangle(*boxToErase)
|
||||
dc.DrawRectangle(*boxToDraw)
|
||||
dc.EndDrawing()
|
||||
|
||||
def __dumpMouseEvent(self, event):
|
||||
print 'Moving: ',event.Moving()
|
||||
print 'Dragging: ',event.Dragging()
|
||||
print 'LeftDown: ',event.LeftDown()
|
||||
print 'LeftisDown: ',event.LeftIsDown()
|
||||
print 'LeftUp: ',event.LeftUp()
|
||||
print 'Position: ',event.GetPosition()
|
||||
print 'x,y: ',event.GetX(),event.GetY()
|
||||
print
|
||||
|
||||
|
||||
#
|
||||
# The public API:
|
||||
#
|
||||
|
||||
def reset(self, aspectRatio=None):
|
||||
"""
|
||||
Clear the existing rubberband
|
||||
"""
|
||||
self.currentBox = None
|
||||
self.aspectRatio = aspectRatio
|
||||
self.drawingSurface.Refresh()
|
||||
|
||||
def getCurrentExtent(self):
|
||||
"""
|
||||
Return (x0, y0, x1, y1) or None if
|
||||
no drawing has yet been done.
|
||||
"""
|
||||
if not self.currentBox:
|
||||
extent = None
|
||||
else:
|
||||
extent = boxToExtent(self.currentBox)
|
||||
return extent
|
||||
|
||||
enabled = property(__isEnabled, __setEnabled, None, 'True if I am responding to mouse events')
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = wxPySimpleApp()
|
||||
frame = wxFrame(None, -1, title='RubberBand Test', size=(300,300))
|
||||
|
||||
# Add a panel that the rubberband will work on.
|
||||
panel = wxPanel(frame, -1)
|
||||
panel.SetBackgroundColour(wxBLUE)
|
||||
|
||||
# Create the rubberband
|
||||
frame.rubberBand = RubberBand(drawingSurface=panel)
|
||||
frame.rubberBand.reset(aspectRatio=0.5)
|
||||
|
||||
# Add a button that creates a new rubberband
|
||||
def __newRubberBand(event):
|
||||
frame.rubberBand.reset()
|
||||
button = wxButton(frame, 100, 'Reset Rubberband')
|
||||
EVT_BUTTON(frame, 100, __newRubberBand)
|
||||
|
||||
# Layout the frame
|
||||
sizer = wxBoxSizer(wxVERTICAL)
|
||||
sizer.Add(panel, 1, wxEXPAND | wxALL, 5)
|
||||
sizer.Add(button, 0, wxALIGN_CENTER | wxALL, 5)
|
||||
frame.SetAutoLayout(1)
|
||||
frame.SetSizer(sizer)
|
||||
frame.Show(1)
|
||||
app.MainLoop()
|
701
wxPython/wxPython/lib/timectrl.py
Normal file
701
wxPython/wxPython/lib/timectrl.py
Normal file
@@ -0,0 +1,701 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: wxTimeCtrl.py
|
||||
# Author: Will Sadkin
|
||||
# Created: 09/19/2002
|
||||
# Copyright: (c) 2002 by Will Sadkin, 2002
|
||||
# License: wxWindows license
|
||||
#----------------------------------------------------------------------------
|
||||
# NOTE:
|
||||
# This was written way it is because of the lack of masked edit controls
|
||||
# in wxWindows/wxPython. I would also have preferred to derive this
|
||||
# control from a wxSpinCtrl rather than wxTextCtrl, but the wxTextCtrl
|
||||
# component of that control is inaccessible through the interface exposed in
|
||||
# wxPython.
|
||||
#
|
||||
# wxTimeCtrl does not use validators, because it does careful manipulation
|
||||
# of the cursor in the text window on each keystroke, and validation is
|
||||
# cursor-position specific, so the control intercepts the key codes before the
|
||||
# validator would fire.
|
||||
#
|
||||
|
||||
from wxPython.wx import *
|
||||
import string
|
||||
|
||||
# The following bit of function is for debugging the subsequent code.
|
||||
# To turn on debugging output, set _debug to 1
|
||||
_debug = 0
|
||||
_indent = 0
|
||||
|
||||
def _dbg(*args, **kwargs):
|
||||
global _indent
|
||||
|
||||
if _debug:
|
||||
if len(args):
|
||||
if _indent: print ' ' * 3 * _indent,
|
||||
for arg in args: print arg,
|
||||
print
|
||||
# else do nothing
|
||||
|
||||
# post process args:
|
||||
for kwarg, value in kwargs.items():
|
||||
if kwarg == 'indent' and value: _indent = _indent + 1
|
||||
elif kwarg == 'indent' and value == 0: _indent = _indent - 1
|
||||
if _indent < 0: _indent = 0
|
||||
|
||||
|
||||
|
||||
# This class of event fires whenever the value of the time changes in the control:
|
||||
wxEVT_TIMEVAL_UPDATED = wxNewId()
|
||||
def EVT_TIMEUPDATE(win, id, func):
|
||||
"""Used to trap events indicating that the current time has been changed."""
|
||||
win.Connect(id, -1, wxEVT_TIMEVAL_UPDATED, func)
|
||||
|
||||
class TimeUpdatedEvent(wxPyCommandEvent):
|
||||
def __init__(self, id, value ='12:00:00 AM'):
|
||||
wxPyCommandEvent.__init__(self, wxEVT_TIMEVAL_UPDATED, id)
|
||||
self.value = value
|
||||
def GetValue(self):
|
||||
"""Retrieve the value of the float control at the time this event was generated"""
|
||||
return self.value
|
||||
|
||||
|
||||
|
||||
class wxTimeCtrl(wxTextCtrl):
|
||||
def __init__ (
|
||||
self, parent, id=-1, value = '12:00:00 AM',
|
||||
pos = wxDefaultPosition, size = wxDefaultSize,
|
||||
fmt24hr=0,
|
||||
spinButton = None,
|
||||
style = wxTE_PROCESS_TAB, name = "time"
|
||||
):
|
||||
wxTextCtrl.__init__(self, parent, id, value='',
|
||||
pos=pos, size=size, style=style, name=name)
|
||||
|
||||
self.__fmt24hr = fmt24hr
|
||||
if size == wxDefaultSize:
|
||||
# set appropriate default sizes depending on format:
|
||||
if self.__fmt24hr:
|
||||
testText = '00:00:00 '
|
||||
else:
|
||||
testText = '00:00:00 XXX'
|
||||
w, h = self.GetTextExtent(testText)
|
||||
self.SetClientSize( (w+4, self.GetClientSize().height) )
|
||||
|
||||
# Set up all the positions of the cells in the wxTimeCtrl (once):
|
||||
# Format of control is:
|
||||
# hh:mm:ss xM
|
||||
# 1
|
||||
# positions: 01234567890
|
||||
|
||||
self.__listCells = ['hour', 'minute', 'second', 'am_pm']
|
||||
self.__listCellRange = [(0,1,2), (3,4,5), (6,7,8), (9,10,11)]
|
||||
self.__listDelimPos = [2,5,8]
|
||||
|
||||
# Create dictionary of cell ranges, indexed by name or position in the range:
|
||||
self.__dictCellRange = {}
|
||||
for i in range(4):
|
||||
self.__dictCellRange[self.__listCells[i]] = self.__listCellRange[i]
|
||||
|
||||
for cell in self.__listCells:
|
||||
for i in self.__dictCellRange[cell]:
|
||||
self.__dictCellRange[i] = self.__dictCellRange[cell]
|
||||
|
||||
|
||||
# Create lists of starting and ending positions for each range, and a dictionary of starting
|
||||
# positions indexed by name
|
||||
self.__listStartCellPos = []
|
||||
self.__listEndCellPos = []
|
||||
for tup in self.__listCellRange:
|
||||
self.__listStartCellPos.append(tup[0]) # 1st char of cell
|
||||
self.__listEndCellPos.append(tup[1]) # last char of cell (not including delimiter)
|
||||
|
||||
self.__dictStartCellPos = {}
|
||||
for i in range(4):
|
||||
self.__dictStartCellPos[self.__listCells[i]] = self.__listStartCellPos[i]
|
||||
|
||||
if self.__fmt24hr: self.__lastCell = 'second'
|
||||
else: self.__lastCell = 'am_pm'
|
||||
|
||||
# Validate initial value and set if appropriate
|
||||
try:
|
||||
self.SetValue(value)
|
||||
except ValueError:
|
||||
self.SetValue('12:00:00 AM')
|
||||
|
||||
# set initial position and selection state
|
||||
self.__SetCurrentCell(self.__dictStartCellPos['hour'])
|
||||
self.__bSelection = false
|
||||
|
||||
EVT_TEXT(self, self.GetId(), self.__OnTextChange)
|
||||
EVT_SET_FOCUS(self, self.__OnFocus)
|
||||
EVT_CHAR(self, self.__OnChar)
|
||||
|
||||
if spinButton:
|
||||
self.BindSpinbutton(spinButton) # bind spin button up/down events to this control
|
||||
|
||||
def __repr__(self):
|
||||
return "<wxTimeCtrl: %s>" % self.GetValue()
|
||||
|
||||
|
||||
def SetValue(self, value):
|
||||
"""
|
||||
Validating SetValue function for time strings, doing 12/24 format conversion as appropriate.
|
||||
"""
|
||||
_dbg('wxTimeCtrl::SetValue', indent=1)
|
||||
dict_range = self.__dictCellRange
|
||||
dict_start = self.__dictStartCellPos
|
||||
|
||||
fmt12len = dict_range['am_pm'][-1]
|
||||
fmt24len = dict_range['second'][-1]
|
||||
try:
|
||||
separators_correct = value[2] == ':' and value[5] == ':'
|
||||
len_ok = len(value) in (fmt12len, fmt24len)
|
||||
|
||||
if len(value) > fmt24len:
|
||||
separators_correct = separators_correct and value[8] == ' '
|
||||
hour = int(value[dict_range['hour'][0]:dict_range['hour'][-1]])
|
||||
hour_ok = ((hour in range(0,24) and len(value) == fmt24len)
|
||||
or (hour in range(1,13) and len(value) == fmt12len
|
||||
and value[dict_start['am_pm']:] in ('AM', 'PM')))
|
||||
|
||||
minute = int(value[dict_range['minute'][0]:dict_range['minute'][-1]])
|
||||
min_ok = minute in range(60)
|
||||
second = int(value[dict_range['second'][0]:dict_range['second'][-1]])
|
||||
sec_ok = second in range(60)
|
||||
|
||||
_dbg('len_ok =', len_ok, 'separators_correct =', separators_correct)
|
||||
_dbg('hour =', hour, 'hour_ok =', hour_ok, 'min_ok =', min_ok, 'sec_ok =', sec_ok)
|
||||
|
||||
if len_ok and hour_ok and min_ok and sec_ok and separators_correct:
|
||||
_dbg('valid time string')
|
||||
|
||||
|
||||
self.__hour = hour
|
||||
if len(value) == fmt12len: # handle 12 hour format conversion for actual hour:
|
||||
am = value[dict_start['am_pm']:] == 'AM'
|
||||
if hour != 12 and not am:
|
||||
self.__hour = hour = (hour+12) % 24
|
||||
elif hour == 12:
|
||||
if am: self.__hour = hour = 0
|
||||
|
||||
self.__minute = minute
|
||||
self.__second = second
|
||||
|
||||
# valid time
|
||||
need_to_convert = ((self.__fmt24hr and len(value) == fmt12len)
|
||||
or (not self.__fmt24hr and len(value) == fmt24len))
|
||||
_dbg('need_to_convert =', need_to_convert)
|
||||
|
||||
if need_to_convert: #convert to 12/24 hour format as specified:
|
||||
dict_start = self.__dictStartCellPos
|
||||
if self.__fmt24hr and len(value) == fmt12len:
|
||||
text = '%.2d:%.2d:%.2d' % (hour, minute, second)
|
||||
else:
|
||||
if hour > 12:
|
||||
hour = hour - 12
|
||||
am_pm = 'PM'
|
||||
elif hour == 12:
|
||||
am_pm = 'PM'
|
||||
else:
|
||||
if hour == 0: hour = 12
|
||||
am_pm = 'AM'
|
||||
text = '%2d:%.2d:%.2d %s' % (hour, minute, second, am_pm)
|
||||
else:
|
||||
text = value
|
||||
_dbg('text=', text)
|
||||
wxTextCtrl.SetValue(self, text)
|
||||
_dbg('firing TimeUpdatedEvent...')
|
||||
evt = TimeUpdatedEvent(self.GetId(), text)
|
||||
evt.SetEventObject(self)
|
||||
self.GetEventHandler().ProcessEvent(evt)
|
||||
else:
|
||||
_dbg('len_ok:', len_ok, 'separators_correct =', separators_correct)
|
||||
_dbg('hour_ok:', hour_ok, 'min_ok:', min_ok, 'sec_ok:', sec_ok, indent=0)
|
||||
raise ValueError, 'value is not a valid time string'
|
||||
|
||||
except (TypeError, ValueError):
|
||||
_dbg(indent=0)
|
||||
raise ValueError, 'value is not a valid time string'
|
||||
_dbg(indent=0)
|
||||
|
||||
def SetFromWxDateTime(self, wxdt):
|
||||
value = '%2d:%.2d:%.2d' % (wxdt.GetHour(), wxdt.GetMinute(), wxdt.GetSecond())
|
||||
self.SetValue(value)
|
||||
|
||||
def GetWxDateTime(self):
|
||||
t = wxDateTimeFromHMS(self.__hour, self.__minute, self.__second)
|
||||
return t
|
||||
|
||||
def SetMxDateTime(self, mxdt):
|
||||
from mx import DateTime
|
||||
value = '%2d:%.2d:%.2d' % (mxdt.hour, mxdt.minute, mxdt.second)
|
||||
self.SetValue(value)
|
||||
|
||||
def GetMxDateTime(self):
|
||||
from mx import DateTime
|
||||
t = DateTime.Time(self.__hour, self.__minute, self.__second)
|
||||
return t
|
||||
|
||||
def BindSpinButton(self, sb):
|
||||
"""
|
||||
This function binds an externally created spin button to the control, so that
|
||||
up/down events from the button automatically change the control.
|
||||
"""
|
||||
_dbg('wxTimeCtrl::BindSpinButton')
|
||||
self.__spinButton = sb
|
||||
if self.__spinButton:
|
||||
EVT_SPIN_UP(self.__spinButton, self.__spinButton.GetId(), self.__OnSpinUp) # bind event handler to spin ctrl
|
||||
EVT_SPIN_DOWN(self.__spinButton, self.__spinButton.GetId(), self.__OnSpinDown) # bind event handler to spin ctrl
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
# these are private functions and overrides:
|
||||
|
||||
def __SetCurrentCell(self, pos):
|
||||
"""
|
||||
Sets state variables that indicate the current cell and position within the control.
|
||||
"""
|
||||
self.__posCurrent = pos
|
||||
self.__cellStart, self.__cellEnd = self.__dictCellRange[pos][0], self.__dictCellRange[pos][-1]
|
||||
|
||||
def SetInsertionPoint(self, pos):
|
||||
"""
|
||||
Records the specified position and associated cell before calling base class' function.
|
||||
"""
|
||||
self.__SetCurrentCell(pos)
|
||||
wxTextCtrl.SetInsertionPoint(self, pos) # (causes EVT_TEXT event to fire)
|
||||
|
||||
|
||||
def __OnTextChange(self, event):
|
||||
"""
|
||||
This private event handler is required to retain the current position information of the cursor
|
||||
after update to the underlying text control is done.
|
||||
"""
|
||||
_dbg('wxTimeCtrl::OnTextChange', indent=1)
|
||||
self.__SetCurrentCell(self.__posCurrent) # ensure cell range vars are set
|
||||
|
||||
# Note: must call self.SetSelection here to preserve insertion point cursor after update!
|
||||
# (I don't know why, but this does the trick!)
|
||||
if self.__bSelection:
|
||||
_dbg('reselecting from ', self.__posCurrent, 'to', self.__posSelectTo)
|
||||
self.SetSelection(self.__posCurrent, self.__posSelectTo)
|
||||
else:
|
||||
self.SetSelection(self.__posCurrent, self.__posCurrent)
|
||||
event.Skip()
|
||||
_dbg(indent=0)
|
||||
|
||||
def __OnFocus(self, event):
|
||||
"""
|
||||
This internal event handler ensures legal setting of input cursor on (re)focus to the control.
|
||||
"""
|
||||
_dbg('wxTimeCtrl::OnFocus; ctrl id=', event.GetId())
|
||||
self.__SetCurrentCell(0)
|
||||
self.__bSelection = false
|
||||
self.__posSelectTo = self.__posCurrent
|
||||
self.SetInsertionPoint(self.__posCurrent)
|
||||
event.Skip()
|
||||
|
||||
|
||||
def __OnSpinUp(self, event):
|
||||
"""
|
||||
Event handler for any bound spin button on EVT_SPIN_UP;
|
||||
causes control to behave as if up arrow was pressed.
|
||||
"""
|
||||
_dbg('wxTimeCtrl::OnSpinUp')
|
||||
pos = self.GetInsertionPoint()
|
||||
self.IncrementValue(WXK_UP, pos)
|
||||
self.SetInsertionPoint(pos)
|
||||
|
||||
def __OnSpinDown(self, event):
|
||||
"""
|
||||
Event handler for any bound spin button on EVT_SPIN_DOWN;
|
||||
causes control to behave as if down arrow was pressed.
|
||||
"""
|
||||
_dbg('wxTimeCtrl::OnSpinDown')
|
||||
pos = self.GetInsertionPoint()
|
||||
self.IncrementValue(WXK_DOWN, pos)
|
||||
self.SetInsertionPoint(pos)
|
||||
|
||||
|
||||
def __OnChar(self, event):
|
||||
"""
|
||||
This private event handler is the main control point for the wxTimeCtrl.
|
||||
It governs whether input characters are accepted and if so, handles them
|
||||
so as to provide appropriate cursor and selection behavior for the control.
|
||||
"""
|
||||
_dbg('wxTimeCtrl::OnChar', indent=1)
|
||||
|
||||
# NOTE: Returning without calling event.Skip() eats the event before it
|
||||
# gets to the text control...
|
||||
|
||||
key = event.GetKeyCode()
|
||||
text = self.GetValue()
|
||||
pos = self.GetInsertionPoint()
|
||||
if pos != self.__posCurrent:
|
||||
_dbg("insertion point has moved; resetting current cell")
|
||||
self.__SetCurrentCell(pos)
|
||||
self.SetSelection(self.__posCurrent, self.__posCurrent)
|
||||
|
||||
sel_start, sel_to = self.GetSelection()
|
||||
selection = sel_start != sel_to
|
||||
if not selection:
|
||||
self.__bSelection = false # predict unselection of entire region
|
||||
|
||||
_dbg('keycode = ', key)
|
||||
_dbg('pos = ', pos)
|
||||
|
||||
if key in (WXK_DELETE, WXK_BACK): # don't allow deletion
|
||||
_dbg(indent=0)
|
||||
return
|
||||
|
||||
elif key == WXK_TAB: # skip to next field if applicable:
|
||||
_dbg('key == WXK_TAB')
|
||||
dict_range = self.__dictCellRange
|
||||
dict_start = self.__dictStartCellPos
|
||||
if event.ShiftDown(): # tabbing backwords
|
||||
|
||||
###(NOTE: doesn't work; wxTE_PROCESS_TAB doesn't appear to send us this event!)
|
||||
|
||||
_dbg('event.ShiftDown()')
|
||||
if pos in dict_range['hour']: # already in 1st field
|
||||
self.__SetCurrentCell(dict_start['hour']) # ensure we have our member vars set
|
||||
event.Skip() #then do normal tab processing for the form
|
||||
|
||||
elif pos in dict_range['minute']: # skip to hours field
|
||||
new_pos = dict_start['hour']
|
||||
elif pos in dict_range['second']: # skip to minutes field
|
||||
new_pos = dict_start['minute']
|
||||
elif pos in dict_range['am_pm']: # skip to seconds field
|
||||
new_pos = dict_start['second']
|
||||
|
||||
self.__bSelection = true
|
||||
self.__posSelectTo = new_pos+2
|
||||
self.SetInsertionPoint(new_pos) # force insert point to jump to next cell (swallowing TAB)
|
||||
|
||||
else:
|
||||
if pos in dict_range[self.__lastCell]: # already in last field; ensure we have our members set
|
||||
self.__SetCurrentCell(dict_start[self.__lastCell])
|
||||
_dbg('tab in last cell')
|
||||
event.Skip() # then do normal tab processing for the form
|
||||
_dbg(indent=0)
|
||||
return
|
||||
|
||||
if pos in dict_range['second']: # skip to AM/PM field (if not last cell)
|
||||
new_pos = dict_start['am_pm']
|
||||
elif pos in dict_range['minute']: # skip to seconds field
|
||||
new_pos = dict_start['second']
|
||||
elif pos in dict_range['hour']: # skip to minutes field
|
||||
new_pos = dict_start['minute']
|
||||
|
||||
self.__bSelection = true
|
||||
self.__posSelectTo = new_pos+2
|
||||
self.SetInsertionPoint(new_pos) # force insert point to jump to next cell (swallowing TAB)
|
||||
|
||||
elif key == WXK_LEFT: # move left; set insertion point as appropriate:
|
||||
_dbg('key == WXK_LEFT')
|
||||
if event.ShiftDown(): # selecting a range...
|
||||
_dbg('event.ShiftDown()')
|
||||
if sel_to != pos:
|
||||
if sel_to - 1 == pos: # allow unselection of position
|
||||
self.__bSelection = false # predict unselection of entire region
|
||||
event.Skip()
|
||||
if pos in self.__listStartCellPos: # can't select pass delimiters
|
||||
_dbg(indent=0)
|
||||
return
|
||||
elif pos in self.__listEndCellPos: # can't use normal selection, because position ends up
|
||||
# at delimeter
|
||||
_dbg('set selection from', pos-1, 'to', self.__posCurrent)
|
||||
self.__bSelection = true
|
||||
self.__posSelectTo = pos
|
||||
self.__posCurrent = pos-1
|
||||
self.SetSelection(self.__posCurrent, self.__posSelectTo)
|
||||
_dbg(indent=0)
|
||||
return
|
||||
else: event.Skip() # allow selection
|
||||
|
||||
# else... not selecting
|
||||
if selection:
|
||||
_dbg('sel_start=', sel_start, 'sel_to=', sel_to, '(Clearing selection)')
|
||||
self.SetSelection(pos,pos) # clear selection
|
||||
self.__bSelection = false
|
||||
|
||||
if pos == 0: # let base ctrl handle left bound case
|
||||
event.Skip()
|
||||
elif pos in self.__listStartCellPos: # skip (left) OVER the colon/space:
|
||||
self.SetInsertionPoint(pos-1) # (this causes a EVT_TEXT)
|
||||
self.__SetCurrentCell(pos-2) # set resulting position as "current"
|
||||
else:
|
||||
self.__SetCurrentCell(pos-1) # record the new cell position after the event is finishedI
|
||||
# and update spinbutton as necessary
|
||||
event.Skip() # let base control handle event
|
||||
|
||||
elif key == WXK_RIGHT: # move right
|
||||
_dbg('key == WXK_RIGHT')
|
||||
if event.ShiftDown():
|
||||
_dbg('event.ShiftDown()')
|
||||
if sel_to in self.__listDelimPos: # can't select pass delimiters
|
||||
_dbg(indent=0)
|
||||
return
|
||||
elif pos in self.__listEndCellPos: # can't use normal selection, because position ends up
|
||||
# at delimeter
|
||||
_dbg('set selection from', self.__posCurrent, 'to', pos+1)
|
||||
self.__bSelection = true
|
||||
self.__posSelectTo = pos+1
|
||||
self.SetSelection(self.__posCurrent, self.__posSelectTo)
|
||||
_dbg(indent=0)
|
||||
return
|
||||
else: event.Skip()
|
||||
|
||||
else:
|
||||
if selection:
|
||||
_dbg('sel_start=', sel_start, 'sel_to=', sel_to, '(Clearing selection)')
|
||||
pos = sel_start
|
||||
self.SetSelection(pos,pos) # clear selection
|
||||
self.__bSelection = false
|
||||
if pos == self.__dictStartCellPos[self.__lastCell]+1:
|
||||
_dbg(indent=0)
|
||||
return # don't allow cursor past last cell
|
||||
if pos in self.__listEndCellPos: # skip (right) OVER the colon/space:
|
||||
self.SetInsertionPoint(pos+1) # (this causes a EVT_TEXT)
|
||||
self.__SetCurrentCell(pos+2) # set resulting position
|
||||
else:
|
||||
self.__SetCurrentCell(pos+1) # record the new cell position after the event is finished
|
||||
self.__bSelection = false
|
||||
event.Skip()
|
||||
|
||||
elif key in (WXK_UP, WXK_DOWN):
|
||||
_dbg('key in (WXK_UP, WXK_DOWN)')
|
||||
self.IncrementValue(key, pos) # increment/decrement as appropriate
|
||||
self.SetInsertionPoint(pos)
|
||||
|
||||
elif key < WXK_SPACE or key == WXK_DELETE or key > 255:
|
||||
event.Skip() # non alphanumeric; process normally (Right thing to do?)
|
||||
|
||||
elif chr(key) in string.digits: # let ChangeValue validate and update current position
|
||||
self.ChangeValue(chr(key), pos) # handle event (and swallow it)
|
||||
|
||||
elif chr(key) in ('A', 'P', 'M', ' '): # let ChangeValue validate and update current position
|
||||
self.ChangeValue(chr(key), pos) # handle event (and swallow it)
|
||||
|
||||
else: # disallowed char; swallow event
|
||||
_dbg(indent=0)
|
||||
return
|
||||
_dbg(indent=0)
|
||||
|
||||
def IncrementValue(self, key, pos):
|
||||
_dbg('wxTimeCtrl::IncrementValue', key, pos)
|
||||
text = self.GetValue()
|
||||
|
||||
sel_start, sel_to = self.GetSelection()
|
||||
selection = sel_start != sel_to
|
||||
cell_selected = selection and sel_to -1 != pos
|
||||
|
||||
dict_start = self.__dictStartCellPos
|
||||
|
||||
# Determine whether we should change the entire cell or just a portion of it:
|
||||
if( not selection
|
||||
or cell_selected
|
||||
or text[pos] == ' '
|
||||
or text[pos] == '9' and text[pos-1] == ' ' and key == WXK_UP
|
||||
or text[pos] == '1' and text[pos-1] == ' ' and key == WXK_DOWN
|
||||
or pos >= dict_start['am_pm']):
|
||||
_dbg(indent=1)
|
||||
self.IncrementCell(key, pos)
|
||||
_dbg(indent=0)
|
||||
else:
|
||||
if key == WXK_UP: inc = 1
|
||||
else: inc = -1
|
||||
|
||||
if pos == dict_start['hour'] and not self.__fmt24hr:
|
||||
if text[pos] == ' ': digit = '1' # allow ' ' or 1 for 1st digit in 12hr format
|
||||
else: digit = ' '
|
||||
else:
|
||||
if pos == dict_start['hour']:
|
||||
if int(text[pos + 1]) >3: mod = 2 # allow for 20-23
|
||||
else: mod = 3 # allow 00-19
|
||||
elif pos == dict_start['hour'] + 1:
|
||||
if self.__fmt24hr:
|
||||
if text[pos - 1] == '2': mod = 4 # allow hours 20-23
|
||||
else: mod = 10 # allow hours 00-19
|
||||
else:
|
||||
if text[pos - 1] == '1': mod = 3 # allow hours 10-12
|
||||
else: mod = 10 # allow 0-9
|
||||
|
||||
elif pos in (dict_start['minute'],
|
||||
dict_start['second']): mod = 6 # allow minutes/seconds 00-59
|
||||
else: mod = 10
|
||||
|
||||
digit = '%d' % ((int(text[pos]) + inc) % mod)
|
||||
|
||||
_dbg(indent=1)
|
||||
_dbg("new digit = \'%s\'" % digit)
|
||||
self.ChangeValue(digit, pos)
|
||||
_dbg(indent=0)
|
||||
|
||||
|
||||
|
||||
def IncrementCell(self, key, pos):
|
||||
_dbg('wxTimeCtrl::IncrementCell', key, pos)
|
||||
self.__SetCurrentCell(pos) # determine current cell
|
||||
hour, minute, second = self.__hour, self.__minute, self.__second
|
||||
text = self.GetValue()
|
||||
dict_start = self.__dictStartCellPos
|
||||
if key == WXK_UP: inc = 1
|
||||
else: inc = -1
|
||||
|
||||
if self.__cellStart == dict_start['am_pm']:
|
||||
am = text[dict_start['am_pm']:] == 'AM'
|
||||
if am: hour = hour + 12
|
||||
else: hour = hour - 12
|
||||
else:
|
||||
if self.__cellStart == dict_start['hour']:
|
||||
hour = (hour + inc) % 24
|
||||
elif self.__cellStart == dict_start['minute']:
|
||||
minute = (minute + inc) % 60
|
||||
elif self.__cellStart == dict_start['second']:
|
||||
second = (second + inc) % 60
|
||||
|
||||
newvalue = '%.2d:%.2d:%.2d' % (hour, minute, second)
|
||||
|
||||
self.__posCurrent = self.__cellStart
|
||||
self.__posSelectTo = self.__cellEnd
|
||||
self.__bSelection = true
|
||||
_dbg(indent=1)
|
||||
self.SetValue(newvalue)
|
||||
_dbg(indent=0)
|
||||
|
||||
|
||||
def ChangeValue(self, char, pos):
|
||||
_dbg('wxTimeCtrl::ChangeValue', "\'" + char + "\'", pos)
|
||||
text = self.GetValue()
|
||||
|
||||
self.__SetCurrentCell(pos)
|
||||
sel_start, sel_to = self.GetSelection()
|
||||
self.__posSelectTo = sel_to
|
||||
self.__bSelection = selection = sel_start != sel_to
|
||||
cell_selected = selection and sel_to -1 != pos
|
||||
|
||||
dict_start = self.__dictStartCellPos
|
||||
|
||||
if pos in self.__listDelimPos: return # don't allow change of punctuation
|
||||
|
||||
elif( 0 < pos < dict_start['am_pm'] and char not in string.digits):
|
||||
return # AM/PM not allowed in this position
|
||||
|
||||
# See if we're changing the hour cell, and validate/update appropriately:
|
||||
#
|
||||
hour_start = dict_start['hour'] # (ie. 0)
|
||||
|
||||
if pos == hour_start: # if at 1st position,
|
||||
if self.__fmt24hr: # and using 24 hour format
|
||||
if char not in ('0', '1', '2'): # return if digit not 0,1, or 2
|
||||
return
|
||||
if cell_selected: # replace cell contents
|
||||
newtext = '%.2d' % int(char) + text[hour_start+2:]
|
||||
else: # relace current position
|
||||
newtext = char + text[pos+1:]
|
||||
else: # (12 hour format)
|
||||
if char not in ('1', ' '): # can only type a 1 or space
|
||||
return
|
||||
if text[pos+1] not in ('0', '1', '2'): # and then, only if other column is 0,1, or 2
|
||||
return
|
||||
if( char == ' ' # and char isn't space and
|
||||
and (cell_selected or text[pos+1] == '0')): # 2nd column is 0 or cell isn't selected
|
||||
return
|
||||
# else... ok
|
||||
if cell_selected: # replace cell contents
|
||||
newtext = '%2d' % int(char) + text[hour_start+2:]
|
||||
else: # relace current position
|
||||
newtext = char + text[pos+1:]
|
||||
if char == ' ': self.SetInsertionPoint(pos+1) # move insert point to legal position
|
||||
|
||||
elif pos == hour_start+1: # if editing 2nd position of hour
|
||||
if( not self.__fmt24hr # and using 12 hour format
|
||||
and text[hour_start] == '1' # if 1st char is 1,
|
||||
and char not in ('0', '1', '2')): # disallow anything bug 0,1, or 2
|
||||
return
|
||||
newtext = text[hour_start] + char + text[hour_start+2:] # else any digit ok
|
||||
|
||||
# Do the same sort of validation for minute and second cells
|
||||
elif pos in (dict_start['minute'], dict_start['second']):
|
||||
if cell_selected: # if cell selected, replace value
|
||||
newtext = text[:pos] + '%.2d' % int(char) + text[pos+2:]
|
||||
elif int(char) > 5: return # else disallow > 59 for minute and second fields
|
||||
else:
|
||||
newtext = text[:pos] + char + text[pos+1:] # else ok
|
||||
|
||||
elif pos in (dict_start['minute']+1, dict_start['second']+1):
|
||||
newtext = text[:pos] + char + text[pos+1:] # all digits ok for 2nd digit of minute/second
|
||||
|
||||
# Process AM/PM cell
|
||||
elif pos == dict_start['am_pm']:
|
||||
if char not in ('A','P'): return # disallow all but A or P as 1st char of column
|
||||
newtext = text[:pos] + char + text[pos+1:]
|
||||
else: return # not a valid position
|
||||
|
||||
# update member position vars and set selection to character changed
|
||||
self.__posCurrent = pos+1
|
||||
self.__SetCurrentCell(self.__posCurrent)
|
||||
_dbg(indent=1)
|
||||
_dbg('newtext=', newtext)
|
||||
_dbg(indent=0)
|
||||
self.SetValue(newtext)
|
||||
self.SetInsertionPoint(pos+1)
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import traceback
|
||||
|
||||
class TestPanel(wxPanel):
|
||||
def __init__(self, parent, id,
|
||||
pos = wxPyDefaultPosition, size = wxPyDefaultSize,
|
||||
fmt24hr = 0, test_mx = 0,
|
||||
style = wxTAB_TRAVERSAL ):
|
||||
|
||||
self.test_mx = test_mx
|
||||
wxPanel.__init__(self, parent, id, pos, size, style)
|
||||
|
||||
sizer = wxBoxSizer( wxHORIZONTAL )
|
||||
self.tc = wxTimeCtrl(self, 10, fmt24hr = fmt24hr)
|
||||
sizer.AddWindow( self.tc, 0, wxALIGN_CENTRE|wxLEFT|wxTOP|wxBOTTOM, 5 )
|
||||
sb = wxSpinButton( self, 20, wxDefaultPosition, wxSize(-1,20), 0 )
|
||||
self.tc.BindSpinButton(sb)
|
||||
sizer.AddWindow( sb, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 )
|
||||
|
||||
self.SetAutoLayout( true )
|
||||
self.SetSizer( sizer )
|
||||
sizer.Fit( self )
|
||||
sizer.SetSizeHints( self )
|
||||
|
||||
EVT_TIMEUPDATE(self, self.tc.GetId(), self.OnTimeChange)
|
||||
|
||||
def OnTimeChange(self, event):
|
||||
_dbg('OnTimeChange: value = ', event.GetValue())
|
||||
wxdt = self.tc.GetWxDateTime()
|
||||
_dbg('wxdt =', wxdt.GetHour(), wxdt.GetMinute(), wxdt.GetSecond())
|
||||
if self.test_mx:
|
||||
mxdt = self.tc.GetMxDateTime()
|
||||
_dbg('mxdt =', mxdt.hour, mxdt.minute, mxdt.second)
|
||||
|
||||
|
||||
class MyApp(wxApp):
|
||||
def OnInit(self):
|
||||
import sys
|
||||
fmt24hr = '24' in sys.argv
|
||||
test_mx = 'mx' in sys.argv
|
||||
try:
|
||||
frame = wxFrame(NULL, -1, "Junk", wxPoint(20,20), wxSize(100,100) )
|
||||
panel = TestPanel(frame, -1, wxPoint(-1,-1), fmt24hr=fmt24hr, test_mx = test_mx)
|
||||
frame.Show(true)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return false
|
||||
return true
|
||||
|
||||
try:
|
||||
app = MyApp(0)
|
||||
app.MainLoop()
|
||||
except:
|
||||
traceback.print_exc()
|
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
img2png.py -- convert several image formats to PNG format
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
img2py.py -- Convert an image to PNG format and embed it in a Python
|
||||
module with appropriate code so it can be loaded into
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
img2xpm.py -- convert several image formats to XPM
|
||||
|
||||
|
Reference in New Issue
Block a user