merged 2.2 branch
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@7748 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
3
wxPython/wxPython/.cvsignore
Normal file
3
wxPython/wxPython/.cvsignore
Normal file
@@ -0,0 +1,3 @@
|
||||
*.py
|
||||
*.pyc
|
||||
*.pyd
|
1
wxPython/wxPython/lib/.cvsignore
Normal file
1
wxPython/wxPython/lib/.cvsignore
Normal file
@@ -0,0 +1 @@
|
||||
*.pyc
|
125
wxPython/wxPython/lib/CDate.py
Normal file
125
wxPython/wxPython/lib/CDate.py
Normal file
@@ -0,0 +1,125 @@
|
||||
# Name: CDate.py
|
||||
# Purpose: Date and Calendar classes
|
||||
#
|
||||
# Author: Lorne White (email: lwhite1@planet.eon.net)
|
||||
#
|
||||
# Created:
|
||||
# Version 0.2 1999/11/08
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
import time
|
||||
|
||||
Month = {2: 'February', 3: 'March', None: 0, 'July': 7, 11:
|
||||
'November', 'December': 12, 'June': 6, 'January': 1, 'September': 9,
|
||||
'August': 8, 'March': 3, 'November': 11, 'April': 4, 12: 'December',
|
||||
'May': 5, 10: 'October', 9: 'September', 8: 'August', 7: 'July', 6:
|
||||
'June', 5: 'May', 4: 'April', 'October': 10, 'February': 2, 1:
|
||||
'January', 0: None}
|
||||
|
||||
# Number of days per month (except for February in leap years)
|
||||
mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
|
||||
# Full and abbreviated names of weekdays
|
||||
day_name = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
|
||||
day_abbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', ]
|
||||
|
||||
# Return number of leap years in range [y1, y2)
|
||||
# Assume y1 <= y2 and no funny (non-leap century) years
|
||||
|
||||
def leapdays(y1, y2):
|
||||
return (y2+3)/4 - (y1+3)/4
|
||||
|
||||
# Return 1 for leap years, 0 for non-leap years
|
||||
def isleap(year):
|
||||
return year % 4 == 0 and (year % 100 <> 0 or year % 400 == 0)
|
||||
|
||||
def FillDate(val):
|
||||
s = str(val)
|
||||
if len(s) < 2:
|
||||
s = '0' + s
|
||||
return s
|
||||
|
||||
|
||||
def julianDay(year, month, day):
|
||||
b = 0L
|
||||
year, month, day = long(year), long(month), long(day)
|
||||
if month > 12L:
|
||||
year = year + month/12L
|
||||
month = month%12
|
||||
elif month < 1L:
|
||||
month = -month
|
||||
year = year - month/12L - 1L
|
||||
month = 12L - month%12L
|
||||
if year > 0L:
|
||||
yearCorr = 0L
|
||||
else:
|
||||
yearCorr = 3L
|
||||
if month < 3L:
|
||||
year = year - 1L
|
||||
month = month + 12L
|
||||
if year*10000L + month*100L + day > 15821014L:
|
||||
b = 2L - year/100L + year/400L
|
||||
return (1461L*year - yearCorr)/4L + 306001L*(month + 1L)/10000L + day + 1720994L + b
|
||||
|
||||
|
||||
def TodayDay():
|
||||
date = time.localtime(time.time())
|
||||
year = date[0]
|
||||
month = date[1]
|
||||
day = date[2]
|
||||
julian = julianDay(year, month, day)
|
||||
daywk = dayOfWeek(julian)
|
||||
daywk = day_name[daywk]
|
||||
return(daywk)
|
||||
|
||||
def FormatDay(value):
|
||||
date = FromFormat(value)
|
||||
daywk = DateCalc.dayOfWeek(date)
|
||||
daywk = day_name[daywk]
|
||||
return(daywk)
|
||||
|
||||
def FromJulian(julian):
|
||||
julian = long(julian)
|
||||
if (julian < 2299160L):
|
||||
b = julian + 1525L
|
||||
else:
|
||||
alpha = (4L*julian - 7468861L)/146097L
|
||||
b = julian + 1526L + alpha - alpha/4L
|
||||
c = (20L*b - 2442L)/7305L
|
||||
d = 1461L*c/4L
|
||||
e = 10000L*(b - d)/306001L
|
||||
day = int(b - d - 306001L*e/10000L)
|
||||
if e < 14L:
|
||||
month = int(e - 1L)
|
||||
else:
|
||||
month = int(e - 13L)
|
||||
if month > 2:
|
||||
year = c - 4716L
|
||||
else:
|
||||
year = c - 4715L
|
||||
year = int(year)
|
||||
return year, month, day
|
||||
|
||||
def dayOfWeek(julian):
|
||||
return int((julian + 1L)%7L)
|
||||
|
||||
def daysPerMonth(month, year):
|
||||
ndays = mdays[month] + (month == 2 and isleap(year))
|
||||
return ndays
|
||||
|
||||
class now:
|
||||
def __init__(self):
|
||||
self.date = time.localtime(time.time())
|
||||
self.year = self.date[0]
|
||||
self.month = self.date[1]
|
||||
self.day = self.date[2]
|
||||
|
||||
class Date:
|
||||
def __init__(self, year, month, day):
|
||||
self.julian = julianDay(year, month, day)
|
||||
self.month = month
|
||||
self.year = year
|
||||
self.day_of_week = dayOfWeek(self.julian)
|
||||
self.days_in_month = daysPerMonth(self.month, self.year)
|
||||
|
3
wxPython/wxPython/lib/__init__.py
Normal file
3
wxPython/wxPython/lib/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
|
140
wxPython/wxPython/lib/activexwrapper.py
Normal file
140
wxPython/wxPython/lib/activexwrapper.py
Normal file
@@ -0,0 +1,140 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.activexwrapper
|
||||
# Purpose: a wxWindow derived class that can hold an ActiveX control
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 2000 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
from wxPython.wx import *
|
||||
|
||||
try:
|
||||
import win32ui
|
||||
import pywin.mfc.activex
|
||||
import win32com.client
|
||||
except ImportError:
|
||||
raise ImportError( "ActiveXWrapper requires PythonWin. Please install the win32all-xxx.exe package.")
|
||||
|
||||
##from win32con import WS_TABSTOP, WS_VISIBLE
|
||||
WS_TABSTOP = 0x00010000
|
||||
WS_VISIBLE = 0x10000000
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
def MakeActiveXClass(CoClass, eventClass=None, eventObj=None):
|
||||
"""
|
||||
Dynamically construct a new class that derives from wxWindow, the
|
||||
ActiveX control and the appropriate COM classes. This new class
|
||||
can be used just like the wxWindow class, but will also respond
|
||||
appropriately to the methods and properties of the COM object. If
|
||||
this class, a derived class or a mix-in class has method names
|
||||
that match the COM objects event names, they will be called
|
||||
automatically.
|
||||
|
||||
CoClass -- A COM control class from a module generated by
|
||||
makepy.py from a COM TypeLibrary. Can also accept a
|
||||
CLSID.
|
||||
|
||||
eventClass -- If given, this class will be added to the set of
|
||||
base classes that the new class is drived from. It is
|
||||
good for mix-in classes for catching events.
|
||||
|
||||
eventObj -- If given, this object will be searched for attributes
|
||||
by the new class's __getattr__ method, (like a mix-in
|
||||
object.) This is useful if you want to catch COM
|
||||
callbacks in an existing object, (such as the parent
|
||||
window.)
|
||||
|
||||
"""
|
||||
|
||||
|
||||
if type(CoClass) == type(""):
|
||||
# use the CLSID to get the real class
|
||||
CoClass = win32com.client.CLSIDToClass(CoClass)
|
||||
|
||||
# determine the base classes
|
||||
axEventClass = CoClass.default_source
|
||||
baseClasses = [wxWindow, pywin.mfc.activex.Control, CoClass, axEventClass]
|
||||
if eventClass:
|
||||
baseClasses.append(eventClass)
|
||||
baseClasses = tuple(baseClasses)
|
||||
|
||||
# define the class attributes
|
||||
className = 'AXControl_'+CoClass.__name__
|
||||
classDict = { '__init__' : axw__init__,
|
||||
'__getattr__' : axw__getattr__,
|
||||
'axw_OnSize' : axw_OnSize,
|
||||
'axw_OEB' : axw_OEB,
|
||||
'_name' : className,
|
||||
'_eventBase' : axEventClass,
|
||||
'_eventObj' : eventObj,
|
||||
'Cleanup' : axw_Cleanup,
|
||||
}
|
||||
|
||||
# make a new class object
|
||||
import new
|
||||
classObj = new.classobj(className, baseClasses, classDict)
|
||||
return classObj
|
||||
|
||||
|
||||
|
||||
|
||||
# These functions will be used as methods in the new class
|
||||
def axw__init__(self, parent, ID, pos=wxDefaultPosition, size=wxDefaultSize, style=0):
|
||||
# init base classes
|
||||
pywin.mfc.activex.Control.__init__(self)
|
||||
wxWindow.__init__(self, parent, -1, pos, size, style)
|
||||
|
||||
win32ui.EnableControlContainer()
|
||||
self._eventObj = self._eventObj # move from class to instance
|
||||
|
||||
# create a pythonwin wrapper around this wxWindow
|
||||
handle = self.GetHandle()
|
||||
self._wnd = win32ui.CreateWindowFromHandle(handle)
|
||||
|
||||
# create the control
|
||||
sz = self.GetSize()
|
||||
self.CreateControl(self._name, WS_TABSTOP | WS_VISIBLE,
|
||||
(0, 0, sz.width, sz.height), self._wnd, ID)
|
||||
|
||||
# init the ax events part of the object
|
||||
self._eventBase.__init__(self, self._dispobj_)
|
||||
|
||||
# hook some wx events
|
||||
EVT_SIZE(self, self.axw_OnSize)
|
||||
EVT_ERASE_BACKGROUND(self, self.axw_OEB)
|
||||
|
||||
|
||||
def axw__getattr__(self, attr):
|
||||
try:
|
||||
return pywin.mfc.activex.Control.__getattr__(self, attr)
|
||||
except AttributeError:
|
||||
try:
|
||||
eo = self.__dict__['_eventObj']
|
||||
return getattr(eo, attr)
|
||||
except AttributeError:
|
||||
raise AttributeError('Attribute not found: %s' % attr)
|
||||
|
||||
|
||||
def axw_OnSize(self, event):
|
||||
sz = self.GetClientSize() # get wxWindow size
|
||||
self.MoveWindow((0, 0, sz.width, sz.height), 1) # move the AXControl
|
||||
|
||||
|
||||
def axw_OEB(self, event):
|
||||
pass
|
||||
|
||||
|
||||
def axw_Cleanup(self):
|
||||
#del self._wnd
|
||||
self.close()
|
||||
## anything else???
|
||||
|
||||
|
||||
|
||||
|
||||
|
423
wxPython/wxPython/lib/buttons.py
Normal file
423
wxPython/wxPython/lib/buttons.py
Normal file
@@ -0,0 +1,423 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.buttons
|
||||
# Purpose: Various kinds of generic buttons, (not native controls but
|
||||
# self-drawn.)
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 9-Dec-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1999 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
This module implements various forms of generic buttons, meaning that
|
||||
they are not built on native controls but are self-drawn.
|
||||
|
||||
The wxGenButton is the base. It acts like a normal button but you
|
||||
are able to better control how it looks, bevel width, colours, etc.
|
||||
|
||||
wxGenBitmapButton is a button with one or more bitmaps that show
|
||||
the various states the button can be in.
|
||||
|
||||
wxGenToggleButton stays depressed when clicked, until clicked again.
|
||||
|
||||
wxGenBitmapToggleButton the same but with bitmaps.
|
||||
|
||||
"""
|
||||
|
||||
from wxPython.wx import *
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class wxGenButtonEvent(wxPyCommandEvent):
|
||||
def __init__(self, eventType, ID):
|
||||
wxPyCommandEvent.__init__(self, eventType, ID)
|
||||
self.isDown = false
|
||||
self.theButton = None
|
||||
|
||||
def SetIsDown(self, isDown):
|
||||
self.isDown = isDown
|
||||
|
||||
def GetIsDown(self):
|
||||
return self.isDown
|
||||
|
||||
def SetButtonObj(self, btn):
|
||||
self.theButton = btn
|
||||
|
||||
def GetButtonObj(self):
|
||||
return self.theButton
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class wxGenButton(wxControl):
|
||||
labelDelta = 1
|
||||
|
||||
def __init__(self, parent, ID, label,
|
||||
pos = wxDefaultPosition, size = wxDefaultSize,
|
||||
style = 0, validator = wxDefaultValidator,
|
||||
name = "genbutton"):
|
||||
if style == 0:
|
||||
style = wxNO_BORDER
|
||||
wxControl.__init__(self, parent, ID, pos, size, style, validator, name)
|
||||
|
||||
self.up = true
|
||||
self.bezelWidth = 2
|
||||
self.hasFocus = false
|
||||
self.useFocusInd = true
|
||||
|
||||
self.SetLabel(label)
|
||||
self.SetPosition(pos)
|
||||
font = parent.GetFont()
|
||||
if not font.Ok():
|
||||
font = wxSystemSettings_GetSystemFont(wxSYS_DEFAULT_GUI_FONT)
|
||||
self.SetFont(font)
|
||||
self.SetBestSize(size)
|
||||
self.InitColours()
|
||||
|
||||
EVT_LEFT_DOWN(self, self.OnLeftDown)
|
||||
EVT_LEFT_UP(self, self.OnLeftUp)
|
||||
EVT_MOTION(self, self.OnMotion)
|
||||
EVT_SET_FOCUS(self, self.OnGainFocus)
|
||||
EVT_KILL_FOCUS(self, self.OnLoseFocus)
|
||||
EVT_KEY_DOWN(self, self.OnKeyDown)
|
||||
EVT_KEY_UP(self, self.OnKeyUp)
|
||||
EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
|
||||
EVT_PAINT(self, self.OnPaint)
|
||||
|
||||
|
||||
def SetBestSize(self, size=None):
|
||||
"""
|
||||
Given the current font and bezel width settings, calculate
|
||||
and set a good size.
|
||||
"""
|
||||
if size is None:
|
||||
size = wxSize(-1,-1)
|
||||
if type(size) == type(()):
|
||||
size = wxSize(size[0], size[1])
|
||||
|
||||
# make a new size so we don't mess with the one passed in
|
||||
size = wxSize(size.width, size.height)
|
||||
|
||||
w, h, useMin = self._GetLabelSize()
|
||||
defSize = wxButton_GetDefaultSize()
|
||||
if size.width == -1:
|
||||
size.width = 12 + w
|
||||
if useMin and size.width < defSize.width:
|
||||
size.width = defSize.width
|
||||
if size.height == -1:
|
||||
size.height = 11 + h
|
||||
if useMin and size.height < defSize.height:
|
||||
size.height = defSize.height
|
||||
|
||||
size.width = size.width + self.bezelWidth - 1
|
||||
size.height = size.height + self.bezelWidth - 1
|
||||
|
||||
self.SetSize(size)
|
||||
|
||||
|
||||
def SetBezelWidth(self, width):
|
||||
"""Set the width of the 3D effect"""
|
||||
self.bezelWidth = width
|
||||
|
||||
def GetBezelWidth(self):
|
||||
"""Return the width of the 3D effect"""
|
||||
return self.bezelWidth
|
||||
|
||||
def SetUseFocusIndicator(self, flag):
|
||||
"""Specifiy if a focus indicator (dotted line) should be used"""
|
||||
self.useFocusInd = flag
|
||||
|
||||
def GetUseFocusIndicator(self):
|
||||
"""Return focus indicator flag"""
|
||||
return self.useFocusInd
|
||||
|
||||
|
||||
def InitColours(self):
|
||||
faceClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNFACE)
|
||||
textClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNTEXT)
|
||||
self.faceDnClr = faceClr
|
||||
self.SetBackgroundColour(faceClr)
|
||||
self.SetForegroundColour(textClr)
|
||||
|
||||
shadowClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNSHADOW)
|
||||
highlightClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNHIGHLIGHT)
|
||||
self.shadowPen = wxPen(shadowClr, 1, wxSOLID)
|
||||
self.highlightPen = wxPen(highlightClr, 1, wxSOLID)
|
||||
##self.focusIndPen = wxPen(textClr, 1, wxUSER_DASH)
|
||||
self.focusIndPen = wxPen(textClr, 1, wxDOT)
|
||||
|
||||
|
||||
def SetBackgroundColour(self, colour):
|
||||
wxWindow.SetBackgroundColour(self, colour)
|
||||
|
||||
# Calculate a new set of highlight and shadow colours based on
|
||||
# the new background colour. Works okay if the colour is dark...
|
||||
r, g, b = colour.Get()
|
||||
fr, fg, fb = min(255,r+32), min(255,g+32), min(255,b+32)
|
||||
self.faceDnClr = wxColour(fr, fg, fb)
|
||||
sr, sg, sb = max(0,r-32), max(0,g-32), max(0,b-32)
|
||||
self.shadowPen = wxPen(wxColour(sr,sg,sb), 1, wxSOLID)
|
||||
hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64)
|
||||
self.highlightPen = wxPen(wxColour(hr,hg,hb), 1, wxSOLID)
|
||||
|
||||
|
||||
def _GetLabelSize(self):
|
||||
""" used internally """
|
||||
w, h = self.GetTextExtent(self.GetLabel())
|
||||
return w, h, true
|
||||
|
||||
|
||||
def Notify(self):
|
||||
evt = wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
|
||||
evt.SetIsDown(not self.up)
|
||||
evt.SetButtonObj(self)
|
||||
self.GetEventHandler().ProcessEvent(evt)
|
||||
|
||||
|
||||
def DrawBezel(self, dc, x1, y1, x2, y2):
|
||||
# draw the upper left sides
|
||||
if self.up:
|
||||
dc.SetPen(self.highlightPen)
|
||||
else:
|
||||
dc.SetPen(self.shadowPen)
|
||||
for i in range(self.bezelWidth):
|
||||
dc.DrawLine(x1+i, y1, x1+i, y2-i)
|
||||
dc.DrawLine(x1, y1+i, x2-i, y1+i)
|
||||
|
||||
# draw the lower right sides
|
||||
if self.up:
|
||||
dc.SetPen(self.shadowPen)
|
||||
else:
|
||||
dc.SetPen(self.highlightPen)
|
||||
for i in range(self.bezelWidth):
|
||||
dc.DrawLine(x1+i, y2-i, x2+1, y2-i)
|
||||
dc.DrawLine(x2-i, y1+i, x2-i, y2)
|
||||
|
||||
|
||||
def DrawLabel(self, dc, width, height, dw=0, dy=0):
|
||||
dc.SetFont(self.GetFont())
|
||||
if self.IsEnabled():
|
||||
dc.SetTextForeground(self.GetForegroundColour())
|
||||
else:
|
||||
dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
|
||||
label = self.GetLabel()
|
||||
tw, th = dc.GetTextExtent(label)
|
||||
if not self.up:
|
||||
dw = dy = self.labelDelta
|
||||
dc.DrawText(label, (width-tw)/2+dw, (height-th)/2+dy)
|
||||
|
||||
|
||||
def DrawFocusIndicator(self, dc, w, h):
|
||||
bw = self.bezelWidth
|
||||
dc.SetLogicalFunction(wxINVERT)
|
||||
self.focusIndPen.SetColour(self.GetForegroundColour())
|
||||
##self.focusIndPen.SetDashes([1,2,1,2]) # This isn't quite working the way I expected...
|
||||
dc.SetPen(self.focusIndPen)
|
||||
dc.SetBrush(wxTRANSPARENT_BRUSH)
|
||||
dc.DrawRectangle(bw+2,bw+2, w-bw*2-4, h-bw*2-4)
|
||||
|
||||
|
||||
def OnPaint(self, event):
|
||||
(width, height) = self.GetClientSizeTuple()
|
||||
x1 = y1 = 0
|
||||
x2 = width-1
|
||||
y2 = height-1
|
||||
dc = wxPaintDC(self)
|
||||
if self.up:
|
||||
dc.SetBackground(wxBrush(self.GetBackgroundColour(), wxSOLID))
|
||||
else:
|
||||
dc.SetBackground(wxBrush(self.faceDnClr, wxSOLID))
|
||||
dc.Clear()
|
||||
self.DrawBezel(dc, x1, y1, x2, y2)
|
||||
self.DrawLabel(dc, width, height)
|
||||
if self.hasFocus and self.useFocusInd:
|
||||
self.DrawFocusIndicator(dc, width, height)
|
||||
|
||||
|
||||
def OnEraseBackground(self, event):
|
||||
pass
|
||||
|
||||
|
||||
def OnLeftDown(self, event):
|
||||
if not self.IsEnabled():
|
||||
return
|
||||
self.up = false
|
||||
self.CaptureMouse()
|
||||
self.SetFocus()
|
||||
self.Refresh()
|
||||
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
if not self.IsEnabled():
|
||||
return
|
||||
if not self.up: # if the button was down when the mouse was released...
|
||||
self.Notify()
|
||||
self.up = true
|
||||
self.ReleaseMouse()
|
||||
self.Refresh()
|
||||
|
||||
|
||||
def OnMotion(self, event):
|
||||
if not self.IsEnabled():
|
||||
return
|
||||
if event.LeftIsDown():
|
||||
x,y = event.GetPositionTuple()
|
||||
w,h = self.GetClientSizeTuple()
|
||||
if self.up and x<w and x>=0 and y<h and y>=0:
|
||||
self.up = false
|
||||
self.Refresh()
|
||||
return
|
||||
if not self.up and (x<0 or y<0 or x>=w or y>=h):
|
||||
self.up = true
|
||||
self.Refresh()
|
||||
return
|
||||
|
||||
|
||||
def OnGainFocus(self, event):
|
||||
self.hasFocus = true
|
||||
dc = wxClientDC(self)
|
||||
w, h = self.GetClientSizeTuple()
|
||||
if self.useFocusInd:
|
||||
self.DrawFocusIndicator(dc, w, h)
|
||||
|
||||
|
||||
def OnLoseFocus(self, event):
|
||||
self.hasFocus = false
|
||||
dc = wxClientDC(self)
|
||||
w, h = self.GetClientSizeTuple()
|
||||
if self.useFocusInd:
|
||||
self.DrawFocusIndicator(dc, w, h)
|
||||
|
||||
|
||||
def OnKeyDown(self, event):
|
||||
if self.hasFocus and event.KeyCode() == ord(" "):
|
||||
self.up = false
|
||||
self.Refresh()
|
||||
event.Skip()
|
||||
|
||||
|
||||
def OnKeyUp(self, event):
|
||||
if self.hasFocus and event.KeyCode() == ord(" "):
|
||||
self.up = true
|
||||
self.Notify()
|
||||
self.Refresh()
|
||||
event.Skip()
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class wxGenBitmapButton(wxGenButton):
|
||||
def __init__(self, parent, ID, bitmap,
|
||||
pos = wxDefaultPosition, size = wxDefaultSize,
|
||||
style = 0, validator = wxDefaultValidator,
|
||||
name = "genbutton"):
|
||||
self.bmpLabel = bitmap
|
||||
self.bmpDisabled = None
|
||||
self.bmpFocus = None
|
||||
self.bmpSelected = None
|
||||
wxGenButton.__init__(self, parent, ID, "", pos, size, style, validator, name)
|
||||
|
||||
|
||||
def GetBitmapLabel(self):
|
||||
return self.bmpLabel
|
||||
def GetBitmapDisabled(self):
|
||||
return self.bmpDisabled
|
||||
def GetBitmapFocus(self):
|
||||
return self.bmpFocus
|
||||
def GetBitmapSelected(self):
|
||||
return self.bmpSelected
|
||||
|
||||
|
||||
def SetBitmapDisabled(self, bitmap):
|
||||
"""Set bitmap to display when the button is disabled"""
|
||||
self.bmpDisabled = bitmap
|
||||
|
||||
def SetBitmapFocus(self, bitmap):
|
||||
"""Set bitmap to display when the button has the focus"""
|
||||
self.bmpFocus = bitmap
|
||||
self.SetUseFocusIndicator(false)
|
||||
|
||||
def SetBitmapSelected(self, bitmap):
|
||||
"""Set bitmap to display when the button is selected (pressed down)"""
|
||||
self.bmpSelected = bitmap
|
||||
|
||||
def SetBitmapLabel(self, bitmap):
|
||||
"""Set the bitmap to display normally. This is the only one that is required."""
|
||||
self.bmpLabel = bitmap
|
||||
|
||||
|
||||
def _GetLabelSize(self):
|
||||
""" used internally """
|
||||
if not self.bmpLabel:
|
||||
return -1, -1, false
|
||||
return self.bmpLabel.GetWidth()+2, self.bmpLabel.GetHeight()+2, false
|
||||
|
||||
|
||||
def DrawLabel(self, dc, width, height, dw=0, dy=0):
|
||||
bmp = self.bmpLabel
|
||||
if self.bmpDisabled and not self.IsEnabled():
|
||||
bmp = self.bmpDisabled
|
||||
if self.bmpFocus and self.hasFocus:
|
||||
bmp = self.bmpFocus
|
||||
if self.bmpSelected and not self.up:
|
||||
bmp = self.bmpSelected
|
||||
bw,bh = bmp.GetWidth(), bmp.GetHeight()
|
||||
if not self.up:
|
||||
dw = dy = self.labelDelta
|
||||
hasMask = bmp.GetMask() != None
|
||||
dc.DrawBitmap(bmp, (width-bw)/2+dw, (height-bh)/2+dy, hasMask)
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
class __ToggleMixin:
|
||||
def SetToggle(self, flag):
|
||||
self.up = not flag
|
||||
|
||||
def GetToggle(self):
|
||||
return not self.up
|
||||
|
||||
def OnLeftDown(self, event):
|
||||
if not self.IsEnabled():
|
||||
return
|
||||
self.saveUp = self.up
|
||||
self.up = not self.up
|
||||
self.CaptureMouse()
|
||||
self.SetFocus()
|
||||
self.Refresh()
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
if not self.IsEnabled():
|
||||
return
|
||||
if self.up != self.saveUp:
|
||||
self.Notify()
|
||||
self.ReleaseMouse()
|
||||
self.Refresh()
|
||||
|
||||
def OnKeyDown(self, event):
|
||||
event.Skip()
|
||||
|
||||
def OnKeyUp(self, event):
|
||||
if self.hasFocus and event.KeyCode() == ord(" "):
|
||||
self.up = not self.up
|
||||
self.Notify()
|
||||
self.Refresh()
|
||||
event.Skip()
|
||||
|
||||
|
||||
|
||||
|
||||
class wxGenToggleButton(__ToggleMixin, wxGenButton):
|
||||
pass
|
||||
|
||||
class wxGenBitmapToggleButton(__ToggleMixin, wxGenBitmapButton):
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
630
wxPython/wxPython/lib/calendar.py
Normal file
630
wxPython/wxPython/lib/calendar.py
Normal file
@@ -0,0 +1,630 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: calendar.py
|
||||
# Purpose: Calendar display control
|
||||
#
|
||||
# Author: Lorne White (email: lwhite1@planet.eon.net)
|
||||
#
|
||||
# Created:
|
||||
# Version 0.6 2000/03/30
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
from wxPython.wx import *
|
||||
|
||||
from CDate import *
|
||||
import string, time
|
||||
|
||||
|
||||
CalDays = [6, 0, 1, 2, 3, 4, 5]
|
||||
AbrWeekday = {6:"Sun", 0:"Mon", 1:"Tue", 2:"Wed", 3:"Thu", 4:"Fri", 5:"Sat"}
|
||||
_MIDSIZE = 160
|
||||
|
||||
BusCalDays = [0, 1, 2, 3, 4, 5, 6]
|
||||
|
||||
# calendar drawing routing
|
||||
|
||||
class CalDraw:
|
||||
def __init__(self, parent):
|
||||
self.pwidth = 1
|
||||
self.pheight = 1
|
||||
try:
|
||||
self.scale = parent.scale
|
||||
except:
|
||||
self.scale = 1
|
||||
|
||||
self.DefParms()
|
||||
|
||||
def DefParms(self):
|
||||
self.grid_color = 'BLACK' # grid and selection colors
|
||||
self.back_color = 'WHITE'
|
||||
self.sel_color = 'RED'
|
||||
|
||||
self.high_color = 'LIGHT BLUE'
|
||||
self.border_color = 'BLACK'
|
||||
self.week_color = 'LIGHT GREY'
|
||||
|
||||
self.week_font_color = 'BLACK' # font colors
|
||||
self.day_font_color = 'BLACK'
|
||||
|
||||
self.font = wxSWISS
|
||||
self.bold = wxNORMAL
|
||||
|
||||
self.hide_title = FALSE
|
||||
self.hide_grid = FALSE
|
||||
self.outer_border = TRUE
|
||||
|
||||
self.title_offset = 0
|
||||
self.cal_week_scale = 0.7
|
||||
self.show_weekend = FALSE
|
||||
self.cal_type = "NORMAL"
|
||||
|
||||
def SetWeekColor(self, font_color, week_color): # set font and background color for week title
|
||||
self.week_font_color = font_color
|
||||
self.week_color = week_color
|
||||
|
||||
def SetSize(self, size):
|
||||
self.set_sizew = size.width
|
||||
self.set_sizeh = size.height
|
||||
|
||||
def InitValues(self): # default dimensions of various elements of the calendar
|
||||
self.rg = {}
|
||||
self.cal_sel = {}
|
||||
self.set_cy_st = 0 # start position
|
||||
self.set_cx_st = 0
|
||||
|
||||
self.set_y_mrg = 15 # start of vertical draw default
|
||||
self.set_x_mrg = 10
|
||||
self.set_y_end = 10
|
||||
|
||||
def SetPos(self, xpos, ypos):
|
||||
self.set_cx_st = xpos
|
||||
self.set_cy_st = ypos
|
||||
|
||||
def SetMarg(self, xmarg, ymarg):
|
||||
self.set_x_st = xmarg
|
||||
self.set_y_st = ymarg
|
||||
self.set_y_end = ymarg
|
||||
|
||||
def InitScale(self): # scale position values
|
||||
self.sizew = self.set_sizew * self.pwidth
|
||||
self.sizeh = self.set_sizeh * self.pheight
|
||||
|
||||
self.cx_st = self.set_cx_st * self.pwidth # draw start position
|
||||
self.cy_st = self.set_cy_st * self.pheight
|
||||
|
||||
self.x_mrg = self.set_x_mrg * self.pwidth # calendar draw margins
|
||||
self.y_mrg = self.set_y_mrg * self.pheight
|
||||
self.y_end = self.set_y_end * self.pheight
|
||||
|
||||
def DrawCal(self, DC, sel_lst=[]):
|
||||
self.DC = DC
|
||||
self.InitScale()
|
||||
|
||||
self.DrawBorder()
|
||||
if self.hide_title is FALSE:
|
||||
self.DrawMonth()
|
||||
|
||||
self.Center()
|
||||
|
||||
self.DrawGrid()
|
||||
self.GetRect()
|
||||
|
||||
if self.show_weekend is TRUE: # highlight weekend dates
|
||||
self.SetWeekEnd()
|
||||
|
||||
self.AddSelect(sel_lst) # overrides the weekend highlight
|
||||
|
||||
self.DrawSel() # highlighted days
|
||||
self.DrawWeek()
|
||||
self.DrawNum()
|
||||
|
||||
def AddSelect(self, list, cfont=None, cbackgrd = None):
|
||||
if cfont is None:
|
||||
cfont = self.sel_color # font digit color
|
||||
if cbackgrd is None:
|
||||
cbackgrd = self.high_color # select background color
|
||||
|
||||
for val in list:
|
||||
self.cal_sel[val] = (cfont, cbackgrd)
|
||||
|
||||
def DrawBorder(self): # draw border around the outside of the main display rectangle
|
||||
brush = wxBrush(wxNamedColour(self.back_color), wxSOLID)
|
||||
self.DC.SetBrush(brush)
|
||||
self.DC.SetPen(wxPen(wxNamedColour(self.border_color), 1))
|
||||
|
||||
if self.outer_border is TRUE:
|
||||
rect = wxRect(self.cx_st, self.cy_st, self.sizew, self.sizeh) # full display window area
|
||||
self.DC.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
|
||||
|
||||
def DrawNumVal(self):
|
||||
self.DrawNum()
|
||||
|
||||
# calculate the calendar days and offset position
|
||||
|
||||
def SetCal(self, year, month):
|
||||
self.InitValues() # reset initial values
|
||||
|
||||
self.year = year
|
||||
self.month = month
|
||||
|
||||
day = 1
|
||||
t = Date(year, month, day)
|
||||
dow = self.dow = t.day_of_week # start day in month
|
||||
dim = self.dim = t.days_in_month # number of days in month
|
||||
if self.cal_type == "NORMAL":
|
||||
start_pos = dow+1
|
||||
else:
|
||||
start_pos = dow
|
||||
|
||||
self.st_pos = start_pos
|
||||
|
||||
self.cal = []
|
||||
for i in range(start_pos):
|
||||
self.cal.append('')
|
||||
i = 1
|
||||
while i <= dim:
|
||||
self.cal.append(str(i))
|
||||
i = i + 1
|
||||
return start_pos
|
||||
|
||||
def SetWeekEnd(self, font_color='BLACK', backgrd = 'LIGHT GREY'):
|
||||
date = 6 - int(self.dow) # start day of first saturday
|
||||
while date <= self.dim:
|
||||
self.cal_sel[date] = (font_color, backgrd) # Saturday
|
||||
date = date + 1
|
||||
if date <= self.dim:
|
||||
self.cal_sel[date] = (font_color, backgrd) # Sunday
|
||||
date = date + 6
|
||||
else:
|
||||
date = date + 7
|
||||
|
||||
def GetRect(self): # get the display rectange list of the day grid
|
||||
cnt = 0
|
||||
for y in self.gridy[1:-1]:
|
||||
for x in self.gridx[:-1]:
|
||||
rect = wxRect(x, y, self.dl_w, self.dl_h) # create rect region
|
||||
self.rg[cnt] = rect
|
||||
cnt = cnt + 1
|
||||
return self.rg
|
||||
|
||||
def GetCal(self):
|
||||
return self.cal
|
||||
|
||||
def GetOffset(self):
|
||||
return self.st_pos
|
||||
|
||||
def DrawMonth(self): # month and year title
|
||||
month = Month[self.month]
|
||||
|
||||
sizef = 11
|
||||
if self.sizeh < _MIDSIZE:
|
||||
sizef = 10
|
||||
|
||||
f = wxFont(sizef, self.font, wxNORMAL, self.bold)
|
||||
self.DC.SetFont(f)
|
||||
|
||||
tw,th = self.DC.GetTextExtent(month)
|
||||
adjust = self.cx_st + (self.sizew-tw)/2
|
||||
self.DC.DrawText(month, adjust, self.cy_st + th)
|
||||
|
||||
year = str(self.year)
|
||||
tw,th = self.DC.GetTextExtent(year)
|
||||
adjust = self.sizew - tw - self.x_mrg
|
||||
|
||||
self.title_offset = th * 2
|
||||
|
||||
f = wxFont(sizef, self.font, wxNORMAL, self.bold)
|
||||
self.DC.SetFont(f)
|
||||
self.DC.DrawText(year, self.cx_st + adjust, self.cy_st + th)
|
||||
|
||||
def DrawWeek(self): # draw the week days
|
||||
sizef = 8
|
||||
if self.sizeh < _MIDSIZE:
|
||||
sizef = 7
|
||||
|
||||
f = wxFont(sizef, self.font, wxNORMAL, self.bold)
|
||||
self.DC.SetFont(f)
|
||||
self.DC.SetTextForeground(wxNamedColour(self.week_font_color))
|
||||
|
||||
cnt_x = 0
|
||||
cnt_y = 0
|
||||
width = self.gridx[1]-self.gridx[0]
|
||||
height = self.gridy[1] - self.gridy[0]
|
||||
|
||||
rect_w = self.gridx[7]-self.gridx[0]
|
||||
|
||||
brush = wxBrush(wxNamedColour(self.week_color), wxSOLID)
|
||||
self.DC.SetBrush(brush)
|
||||
# self.DC.DrawRectangle(self.gridx[0], self.gridy[0], rect_w+1, height)
|
||||
|
||||
if self.cal_type == "NORMAL":
|
||||
cal_days = CalDays
|
||||
else:
|
||||
cal_days = BusCalDays
|
||||
|
||||
for val in cal_days:
|
||||
day = AbrWeekday[val]
|
||||
if self.sizew < 200:
|
||||
day = day[0]
|
||||
dw,dh = self.DC.GetTextExtent(day)
|
||||
diffx = (width-dw)/2
|
||||
diffy = (height-dh)/2
|
||||
|
||||
x = self.gridx[cnt_x]
|
||||
y = self.gridy[cnt_y]
|
||||
self.DC.DrawRectangle(self.gridx[cnt_x], self.gridy[0], width+1, height)
|
||||
self.DC.DrawText(day, x+diffx, y+diffy)
|
||||
cnt_x = cnt_x + 1
|
||||
|
||||
|
||||
def DrawNum(self): # draw the day numbers
|
||||
sizef = 10
|
||||
if self.sizeh < _MIDSIZE:
|
||||
sizef = 8
|
||||
f = wxFont(sizef, self.font, wxNORMAL, self.bold)
|
||||
|
||||
cnt_x = 0
|
||||
cnt_y = 1
|
||||
for val in self.cal:
|
||||
x = self.gridx[cnt_x]
|
||||
y = self.gridy[cnt_y]
|
||||
|
||||
try:
|
||||
num_val = int(val)
|
||||
num_color = self.cal_sel[num_val][0]
|
||||
except:
|
||||
num_color = self.day_font_color
|
||||
|
||||
self.DC.SetTextForeground(wxNamedColour(num_color))
|
||||
self.DC.SetFont(f)
|
||||
|
||||
self.DC.DrawText(val, x+5, y+5)
|
||||
if cnt_x < 6:
|
||||
cnt_x = cnt_x + 1
|
||||
else:
|
||||
cnt_x = 0
|
||||
cnt_y = cnt_y + 1
|
||||
|
||||
def Center(self): # calculate the dimensions in the center of the drawing area
|
||||
bdw = self.x_mrg * 2
|
||||
bdh = self.y_mrg + self.y_end + self.title_offset
|
||||
|
||||
self.dl_w = int((self.sizew-bdw)/7)
|
||||
self.dl_h = int((self.sizeh-bdh)/7)
|
||||
|
||||
self.dl_th = int(self.dl_h*self.cal_week_scale) # week title adjustment
|
||||
self.cwidth = self.dl_w * 7
|
||||
self.cheight = self.dl_h * 6 + self.dl_th
|
||||
|
||||
def DrawSel(self): # highlighted selected days
|
||||
for key in self.cal_sel.keys():
|
||||
sel_color = self.cal_sel[key][1]
|
||||
brush = wxBrush(wxNamedColour(sel_color), wxSOLID)
|
||||
self.DC.SetBrush(brush)
|
||||
|
||||
if self.hide_grid is FALSE:
|
||||
self.DC.SetPen(wxPen(wxNamedColour(self.grid_color), 0))
|
||||
else:
|
||||
self.DC.SetPen(wxPen(wxNamedColour(self.back_color), 0))
|
||||
nkey = key + self.st_pos -1
|
||||
rect = self.rg[nkey]
|
||||
self.DC.DrawRectangle(rect.x, rect.y, rect.width+1, rect.height+1)
|
||||
|
||||
def DrawGrid(self): # calculate and draw the grid lines
|
||||
self.DC.SetPen(wxPen(wxNamedColour(self.grid_color), 0))
|
||||
|
||||
self.gridx = []
|
||||
self.gridy = []
|
||||
|
||||
self.x_st = self.cx_st + self.x_mrg
|
||||
self.y_st = self.cy_st + self.y_mrg + self.title_offset # start postion of draw
|
||||
|
||||
x1 = self.x_st
|
||||
y1 = self.y_st
|
||||
|
||||
y2 = y1 + self.cheight
|
||||
for i in range(8):
|
||||
if self.hide_grid is FALSE:
|
||||
self.DC.DrawLine(x1, y1, x1, y2)
|
||||
self.gridx.append(x1)
|
||||
x1 = x1 + self.dl_w
|
||||
|
||||
x1 = self.x_st
|
||||
y1 = self.y_st
|
||||
|
||||
x2 = x1 + self.cwidth
|
||||
for i in range(8):
|
||||
if self.hide_grid is FALSE:
|
||||
self.DC.DrawLine(x1, y1, x2, y1)
|
||||
self.gridy.append(y1)
|
||||
if i == 0:
|
||||
y1 = y1 + self.dl_th
|
||||
else:
|
||||
y1 = y1 + self.dl_h
|
||||
|
||||
|
||||
class PrtCalDraw(CalDraw):
|
||||
def InitValues(self):
|
||||
self.rg = {}
|
||||
self.cal_sel = {}
|
||||
self.set_cx_st = 1.0 # start draw border location
|
||||
self.set_cy_st = 1.0
|
||||
|
||||
self.set_y_mrg = 0.2 # draw offset position
|
||||
self.set_x_mrg = 0.2
|
||||
self.set_y_end = 0.2
|
||||
|
||||
def SetPSize(self, pwidth, pheight): # calculate the dimensions in the center of the drawing area
|
||||
self.pwidth = int(pwidth)/self.scale
|
||||
self.pheight = int(pheight)/self.scale
|
||||
|
||||
def SetPreview(self, preview):
|
||||
self.preview = preview
|
||||
|
||||
class wxCalendar(wxWindow):
|
||||
def __init__(self, parent, id, pos=wxDefaultPosition, size=wxDefaultSize):
|
||||
wxWindow.__init__(self, parent, id, pos, size)
|
||||
|
||||
# set the calendar control attributes
|
||||
|
||||
self.grid_color = 'BLACK'
|
||||
self.back_color = 'WHITE'
|
||||
self.hide_grid = FALSE
|
||||
self.sel_color = 'RED'
|
||||
self.hide_title = FALSE
|
||||
self.show_weekend = FALSE
|
||||
self.cal_type = "NORMAL"
|
||||
|
||||
self.week_color = 'LIGHT GREY'
|
||||
self.week_font_color = 'BLACK' # font colors
|
||||
|
||||
self.select_list = []
|
||||
|
||||
self.SetBackgroundColour(wxNamedColor(self.back_color))
|
||||
self.Connect(-1, -1, wxEVT_LEFT_DOWN, self.OnLeftEvent)
|
||||
self.Connect(-1, -1, wxEVT_LEFT_DCLICK, self.OnLeftDEvent)
|
||||
self.Connect(-1, -1, wxEVT_RIGHT_DOWN, self.OnRightEvent)
|
||||
self.Connect(-1, -1, wxEVT_RIGHT_DCLICK, self.OnRightDEvent)
|
||||
|
||||
self.sel_key = None # last used by
|
||||
self.sel_lst = [] # highlighted selected days
|
||||
|
||||
self.SetNow() # default calendar for current month
|
||||
|
||||
self.size = None
|
||||
self.set_day = None
|
||||
|
||||
EVT_PAINT(self, self.OnPaint)
|
||||
|
||||
|
||||
# control some of the main calendar attributes
|
||||
|
||||
def HideTitle(self):
|
||||
self.hide_title = TRUE
|
||||
|
||||
def HideGrid(self):
|
||||
self.hide_grid = TRUE
|
||||
|
||||
# determine the calendar rectangle click area and draw a selection
|
||||
|
||||
def ProcessClick(self, event):
|
||||
self.x, self.y = event.GetX(), event.GetY()
|
||||
key = self.GetDayHit(self.x, self.y)
|
||||
self.SelectDay(key)
|
||||
|
||||
# tab mouse click events and process
|
||||
|
||||
def OnLeftEvent(self, event):
|
||||
self.click = 'LEFT'
|
||||
self.ProcessClick(event)
|
||||
|
||||
def OnLeftDEvent(self, event):
|
||||
self.click = 'DLEFT'
|
||||
self.ProcessClick(event)
|
||||
|
||||
def OnRightEvent(self, event):
|
||||
self.click = 'RIGHT'
|
||||
self.ProcessClick(event)
|
||||
|
||||
def OnRightDEvent(self, event):
|
||||
self.click = 'DRIGHT'
|
||||
self.ProcessClick(event)
|
||||
|
||||
def SetSize(self, set_size):
|
||||
self.size = set_size
|
||||
|
||||
def SetSelDay(self, sel):
|
||||
self.sel_lst = sel # list of highlighted days
|
||||
|
||||
# get the current date
|
||||
|
||||
def SetNow(self):
|
||||
dt = now()
|
||||
self.month = dt.month
|
||||
self.year = dt.year
|
||||
self.day = dt.day
|
||||
|
||||
# set the current day
|
||||
|
||||
def SetCurrentDay(self):
|
||||
self.SetNow()
|
||||
self.set_day = self.day
|
||||
|
||||
# get the date, day, month, year set in calendar
|
||||
|
||||
def GetDate(self):
|
||||
return self.day, self.month, self.year
|
||||
|
||||
def GetDay(self):
|
||||
return self.day
|
||||
|
||||
def GetMonth(self):
|
||||
return self.month
|
||||
|
||||
def GetYear(self):
|
||||
return self.year
|
||||
|
||||
# set the day, month, and year
|
||||
|
||||
def SetDayValue(self, day):
|
||||
self.set_day = day
|
||||
|
||||
def SetMonth(self, month):
|
||||
if month >= 1 and month <= 12:
|
||||
self.month = month
|
||||
else:
|
||||
self.month = 1
|
||||
self.set_day = None
|
||||
|
||||
def SetYear(self, year):
|
||||
self.year = year
|
||||
|
||||
# increment year and month
|
||||
|
||||
def IncYear(self):
|
||||
self.year = self.year + 1
|
||||
self.set_day = None
|
||||
|
||||
def DecYear(self):
|
||||
self.year = self.year - 1
|
||||
self.set_day = None
|
||||
|
||||
def IncMonth(self):
|
||||
self.month = self.month + 1
|
||||
if self.month > 12:
|
||||
self.month = 1
|
||||
self.year = self.year + 1
|
||||
self.set_day = None
|
||||
|
||||
def DecMonth(self):
|
||||
self.month = self.month - 1
|
||||
if self.month < 1:
|
||||
self.month = 12
|
||||
self.year = self.year - 1
|
||||
self.set_day = None
|
||||
|
||||
# test to see if the selection has a date and create event
|
||||
|
||||
def TestDay(self, key):
|
||||
try:
|
||||
self.day = int(self.cal[key])
|
||||
except:
|
||||
return None
|
||||
if self.day == "":
|
||||
return None
|
||||
else:
|
||||
evt = wxPyCommandEvent(2100, self.GetId())
|
||||
evt.click, evt.day, evt.month, evt.year = self.click, self.day, self.month, self.year
|
||||
self.GetEventHandler().ProcessEvent(evt)
|
||||
|
||||
self.set_day = self.day
|
||||
return key
|
||||
|
||||
# find the clicked area rectangle
|
||||
|
||||
def GetDayHit(self, mx, my):
|
||||
for key in self.rg.keys():
|
||||
val = self.rg[key]
|
||||
ms_rect = wxRect(mx, my, 1, 1)
|
||||
if wxIntersectRect(ms_rect, val) is not None:
|
||||
result = self.TestDay(key)
|
||||
return result
|
||||
return None
|
||||
|
||||
# calendar drawing
|
||||
|
||||
def SetWeekColor(self, font_color, week_color): # set font and background color for week title
|
||||
self.week_font_color = font_color
|
||||
self.week_color = week_color
|
||||
|
||||
def AddSelect(self, list, font_color, back_color):
|
||||
list_val = [list, font_color, back_color]
|
||||
self.select_list.append(list_val)
|
||||
|
||||
def ShowWeekEnd(self):
|
||||
self.show_weekend = TRUE # highlight weekend
|
||||
|
||||
def SetBusType(self):
|
||||
self.cal_type = "BUS"
|
||||
|
||||
def OnPaint(self, event):
|
||||
DC = wxPaintDC(self)
|
||||
self.DoDrawing(DC)
|
||||
|
||||
def DoDrawing(self, DC):
|
||||
DC = wxPaintDC(self)
|
||||
DC.BeginDrawing()
|
||||
|
||||
self.cal = cal = CalDraw(self)
|
||||
|
||||
cal.grid_color = self.grid_color
|
||||
cal.back_color = self.back_color
|
||||
cal.hide_grid = self.hide_grid
|
||||
cal.grid_color = self.grid_color
|
||||
cal.hide_title = self.hide_title
|
||||
cal.show_weekend = self.show_weekend
|
||||
cal.cal_type = self.cal_type
|
||||
|
||||
if self.size is None:
|
||||
size = self.GetClientSize()
|
||||
else:
|
||||
size = self.size
|
||||
|
||||
# drawing attributes
|
||||
|
||||
cal.week_font_color = self.week_font_color
|
||||
cal.week_color = self.week_color
|
||||
|
||||
cal.SetSize(size)
|
||||
cal.SetCal(self.year, self.month)
|
||||
for val in self.select_list:
|
||||
cal.AddSelect(val[0], val[1], val[2])
|
||||
|
||||
cal.DrawCal(DC, self.sel_lst)
|
||||
|
||||
self.rg = cal.GetRect()
|
||||
self.cal = cal.GetCal()
|
||||
self.st_pos = cal.GetOffset()
|
||||
self.ymax = DC.MaxY()
|
||||
|
||||
if self.set_day != None:
|
||||
self.SetDay(self.set_day)
|
||||
DC.EndDrawing()
|
||||
|
||||
# draw the selection rectangle
|
||||
|
||||
def DrawRect(self, key, color = 'BLACK', width = 0):
|
||||
if key == None:
|
||||
return
|
||||
DC = wxClientDC(self)
|
||||
DC.BeginDrawing()
|
||||
|
||||
brush = wxBrush(wxColour(0, 0xFF, 0x80), wxTRANSPARENT)
|
||||
DC.SetBrush(brush)
|
||||
DC.SetPen(wxPen(wxNamedColour(color), width))
|
||||
|
||||
rect = self.rg[key]
|
||||
DC.DrawRectangle(rect.x, rect.y, rect.width+1, rect.height+1)
|
||||
|
||||
DC.EndDrawing()
|
||||
|
||||
# set the day selection
|
||||
|
||||
def SetDay(self, day):
|
||||
day = day + self.st_pos - 1
|
||||
self.SelectDay(day)
|
||||
|
||||
def SelectDay(self, key):
|
||||
sel_size = 1
|
||||
self.DrawRect(self.sel_key, self.back_color, sel_size) # clear large selection
|
||||
if self.hide_grid is FALSE:
|
||||
self.DrawRect(self.sel_key, self.grid_color)
|
||||
|
||||
self.DrawRect(key, self.sel_color, sel_size)
|
||||
self.sel_key = key # store last used by
|
||||
self.select_day = None
|
||||
|
||||
def ClearDsp(self):
|
||||
self.Clear()
|
||||
|
||||
|
108
wxPython/wxPython/lib/dialogs.py
Normal file
108
wxPython/wxPython/lib/dialogs.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from wxPython.wx import *
|
||||
from layoutf import Layoutf
|
||||
import string
|
||||
|
||||
|
||||
|
||||
class wxScrolledMessageDialog(wxDialog):
|
||||
|
||||
def __init__(self, parent, msg, caption, pos = None, size = None):
|
||||
if not pos:
|
||||
pos = wxDefaultPosition
|
||||
if not size:
|
||||
size = wxSize(500,300)
|
||||
wxDialog.__init__(self, parent, -1, caption, pos, size)
|
||||
text = wxTextCtrl(self, -1, msg, wxDefaultPosition,
|
||||
wxDefaultSize,
|
||||
wxTE_MULTILINE | wxTE_READONLY)
|
||||
ok = wxButton(self, wxID_OK, "OK")
|
||||
text.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok)))
|
||||
ok.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self,)))
|
||||
self.SetAutoLayout(TRUE)
|
||||
self.Layout()
|
||||
|
||||
|
||||
class wxMultipleChoiceDialog(wxDialog):
|
||||
|
||||
def __init__(self, parent, msg, title, lst, pos = None, size = None):
|
||||
if not pos:
|
||||
pos = wxDefaultPosition
|
||||
if not size:
|
||||
size = wxSize(200,200)
|
||||
wxDialog.__init__(self, parent, -1, title, pos, size)
|
||||
dc = wxClientDC(self)
|
||||
height = 0
|
||||
for line in string.split(msg,'\n'):
|
||||
height = height + dc.GetTextExtent(msg)[1] + 4
|
||||
stat = wxStaticText(self, -1, msg)
|
||||
self.lbox = wxListBox(self, 100, wxDefaultPosition,
|
||||
wxDefaultSize, lst, wxLB_MULTIPLE)
|
||||
ok = wxButton(self, wxID_OK, "OK")
|
||||
cancel = wxButton(self, wxID_CANCEL, "Cancel")
|
||||
stat.SetConstraints(Layoutf('t=t10#1;l=l5#1;r=r5#1;h!%d' % (height,),
|
||||
(self,)))
|
||||
self.lbox.SetConstraints(Layoutf('t=b10#2;l=l5#1;r=r5#1;b=t5#3',
|
||||
(self, stat, ok)))
|
||||
ok.SetConstraints(Layoutf('b=b5#1;x%w25#1;w!80;h!25', (self,)))
|
||||
cancel.SetConstraints(Layoutf('b=b5#1;x%w75#1;w!80;h!25', (self,)))
|
||||
self.SetAutoLayout(TRUE)
|
||||
self.lst = lst
|
||||
self.Layout()
|
||||
EVT_SIZE(self, self.OnSize)
|
||||
|
||||
def OnSize(self, event):
|
||||
self.Layout()
|
||||
|
||||
def GetValue(self):
|
||||
return self.lbox.GetSelections()
|
||||
|
||||
def GetValueString(self):
|
||||
sel = self.lbox.GetSelections()
|
||||
val = []
|
||||
for i in sel:
|
||||
val.append(self.lst[i])
|
||||
return tuple(val)
|
||||
|
||||
if __name__ == '__main__':
|
||||
class MyFrame(wxFrame):
|
||||
def __init__(self):
|
||||
wxFrame.__init__(self, NULL, -1, "hello",
|
||||
wxDefaultPosition, wxSize(200,200))
|
||||
wxButton(self, 100, "Multiple Test",wxPoint(0,0))
|
||||
wxButton(self, 101, "Message Test", wxPoint(0,100))
|
||||
EVT_BUTTON(self, 100, self.OnMultipleTest)
|
||||
EVT_BUTTON(self, 101, self.OnMessageTest)
|
||||
|
||||
def OnMultipleTest(self, event):
|
||||
self.lst = [ 'apple', 'pear', 'banana', 'coconut', 'orange',
|
||||
'etc', 'etc..', 'etc...' ]
|
||||
dlg = wxMultipleChoiceDialog(self,
|
||||
"Pick some from\n this list\nblabla",
|
||||
"m.s.d.", self.lst)
|
||||
if (dlg.ShowModal() == wxID_OK):
|
||||
print "Selection:", dlg.GetValue(), " -> ", dlg.GetValueString()
|
||||
|
||||
def OnMessageTest(self, event):
|
||||
import sys;
|
||||
f = open(sys.argv[0],"r")
|
||||
msg = f.read()
|
||||
dlg = wxScrolledMessageDialog(self, msg, "message test")
|
||||
dlg.ShowModal()
|
||||
|
||||
|
||||
class MyApp(wxApp):
|
||||
def OnInit(self):
|
||||
frame = MyFrame()
|
||||
frame.Show(TRUE)
|
||||
self.SetTopWindow(frame)
|
||||
return TRUE
|
||||
|
||||
app = MyApp(0)
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
4
wxPython/wxPython/lib/editor/.cvsignore
Normal file
4
wxPython/wxPython/lib/editor/.cvsignore
Normal file
@@ -0,0 +1,4 @@
|
||||
__init__.pyc
|
||||
editor.pyc
|
||||
py_editor.pyc
|
||||
tokenizer.pyc
|
10
wxPython/wxPython/lib/editor/README.txt
Normal file
10
wxPython/wxPython/lib/editor/README.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
PLEASE NOTE: This is experimental code. It needs an overhall in the
|
||||
drawing and update code, and there is occasionally a
|
||||
mysteriously disappearing line...
|
||||
|
||||
I am working on a StyledTextEditor that will likely
|
||||
render this editor obsolete... But this one is at
|
||||
least somewhat functional now while the other is still
|
||||
vapor.
|
||||
|
||||
- Robin
|
18
wxPython/wxPython/lib/editor/__init__.py
Normal file
18
wxPython/wxPython/lib/editor/__init__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.editor
|
||||
# Purpose: A package containing a colourizable text editror
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 30-Dec-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1999 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# This file makes this directory into a Python package
|
||||
|
||||
|
||||
# import the main classes into the package namespace.
|
||||
from editor import wxEditor
|
||||
from py_editor import wxPyEditor
|
670
wxPython/wxPython/lib/editor/editor.py
Normal file
670
wxPython/wxPython/lib/editor/editor.py
Normal file
@@ -0,0 +1,670 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.editor.wxEditor
|
||||
# Purpose: An intelligent text editor with colorization capabilities.
|
||||
#
|
||||
# Author: Dirk Holtwic, Robin Dunn
|
||||
#
|
||||
# Created: 15-Dec-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1999 by Dirk Holtwick, 1999
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
# PLEASE NOTE: This is experimental code. It needs an overhall in the
|
||||
# drawing and update code, and there is occasionally a
|
||||
# mysteriously disappearing line...
|
||||
#
|
||||
# I am working on a StyledTextEditor that will likely
|
||||
# render this editor obsolete... But this one is at
|
||||
# least somewhat functional now while the other is still
|
||||
# vapor.
|
||||
#
|
||||
# - Robin
|
||||
|
||||
|
||||
from wxPython.wx import *
|
||||
from string import *
|
||||
from keyword import *
|
||||
from regsub import *
|
||||
from tokenizer import *
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class Line:
|
||||
def __init__(self, text=""):
|
||||
self.text = text # the string itself
|
||||
self.syntax = [] # the colors of the line
|
||||
self.editable = true # edit?
|
||||
self.visible = 0 # will be incremented if not
|
||||
self.indent = 0 # not used yet
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class wxEditor(wxScrolledWindow):
|
||||
|
||||
def __init__(self, parent, id,
|
||||
pos=wxDefaultPosition, size=wxDefaultSize, style=0):
|
||||
###############################################################
|
||||
"""
|
||||
Alles hat einen Anfang
|
||||
"""
|
||||
|
||||
wxScrolledWindow.__init__(self, parent, id,
|
||||
pos, size,
|
||||
style|wxWANTS_CHARS)
|
||||
|
||||
# the syntax informations, if they don't exist,
|
||||
# all syntax stuff will be ignored
|
||||
|
||||
# cursor pos
|
||||
self.cx = 0
|
||||
self.cy = 0
|
||||
|
||||
# the lines that are visible
|
||||
self.lines = []
|
||||
self.line = 0
|
||||
self.len = 0
|
||||
|
||||
self.ocy = 0
|
||||
|
||||
# border pos
|
||||
#self.bx = 0
|
||||
#self.by = 0
|
||||
|
||||
# screen
|
||||
self.sx = 0
|
||||
self.sy = 0
|
||||
self.sw = 0
|
||||
self.sh = 0
|
||||
self.osx= 0
|
||||
self.osy= 0
|
||||
|
||||
# font
|
||||
dc = wxClientDC(self)
|
||||
|
||||
if wxPlatform == "__WXMSW__":
|
||||
self.font = wxFont(10, wxMODERN, wxNORMAL, wxNORMAL)
|
||||
else:
|
||||
self.font = wxFont(12, wxMODERN, wxNORMAL, wxNORMAL, false)
|
||||
dc.SetFont(self.font)
|
||||
|
||||
# font weight, height
|
||||
self.fw = dc.GetCharWidth()
|
||||
self.fh = dc.GetCharHeight()
|
||||
|
||||
# back, for colour
|
||||
self.bcol = wxNamedColour('white')
|
||||
self.fcol = wxNamedColour('black')
|
||||
|
||||
self.cfcol = wxNamedColour('black')
|
||||
self.cbcol = wxNamedColour('red')
|
||||
|
||||
# nicht edierbare zeile (hintergrund)
|
||||
self.nedcol = wxNamedColour('grey')
|
||||
|
||||
self.SetBackgroundColour(self.bcol)
|
||||
#dc.SetForegroundColour(self.fcol)
|
||||
|
||||
# events
|
||||
EVT_LEFT_DOWN(self, self.OnMouseClick)
|
||||
EVT_RIGHT_DOWN(self, self.OnMouseClick)
|
||||
EVT_SCROLLWIN(self, self.OnScroll)
|
||||
EVT_CHAR(self, self.OnChar)
|
||||
EVT_PAINT(self, self.OnPaint)
|
||||
|
||||
self.o_cx = self.cx
|
||||
self.o_cy = self.cy
|
||||
self.o_sx = self.sx
|
||||
self.o_sy = self.sy
|
||||
self.o_line = self.line
|
||||
self.sco_x = 0
|
||||
self.sco_y = 0
|
||||
|
||||
self.tabsize = 4
|
||||
|
||||
self.update = true
|
||||
self.in_scroll =FALSE
|
||||
self.inUpdate = FALSE
|
||||
|
||||
|
||||
bw,bh = self.GetSizeTuple()
|
||||
# double buffering
|
||||
self.mdc = wxMemoryDC()
|
||||
self.mdc.SelectObject(wxEmptyBitmap(bw,bh))
|
||||
# disable physical scrolling because invisible parts are not drawn
|
||||
self.EnableScrolling(FALSE, FALSE)
|
||||
|
||||
# the ordinary text as it is
|
||||
self.SetText()
|
||||
self.SetFocus()
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def CalcLines(self):
|
||||
###############################################################
|
||||
self.lines = []
|
||||
x =maxlen =0
|
||||
for line in self.text:
|
||||
if line.visible==0:
|
||||
self.lines.append(x)
|
||||
else:
|
||||
if len(line.text) >maxlen:
|
||||
maxlen =len(line.text)
|
||||
x = x + 1
|
||||
self.len = len(self.lines)
|
||||
self.max_linelength =maxlen
|
||||
|
||||
|
||||
def SetFontTab(self, fonttab):
|
||||
###############################################################
|
||||
""" Fonttabelle zum schnellen Zugriff """
|
||||
self.ftab = fonttab
|
||||
|
||||
|
||||
def SetText(self, text = [""]):
|
||||
###############################################################
|
||||
""" Text mittels Liste setzen """
|
||||
self.cx = 0
|
||||
self.cy = 0
|
||||
self.text = []
|
||||
|
||||
for t in text:
|
||||
self.text.append(Line(t))
|
||||
|
||||
for l in range(0,len(text)-1):
|
||||
#self.UpdateSyntax(l)
|
||||
self.OnUpdateHighlight(l)
|
||||
|
||||
self.OnInit()
|
||||
|
||||
self.update = true
|
||||
self.UpdateView(None, true)
|
||||
|
||||
|
||||
# show new text
|
||||
def GetText(self):
|
||||
###############################################################
|
||||
""" Der gesamte Text als Liste """
|
||||
text = []
|
||||
for line in self.text:
|
||||
text.append(line.text)
|
||||
return text
|
||||
|
||||
|
||||
def IsEmpty(self):
|
||||
###############################################################
|
||||
"""see if at least one text line is not empty"""
|
||||
for line in self.text:
|
||||
if line.text: return 0
|
||||
return 1
|
||||
|
||||
|
||||
def IsLine(self, line):
|
||||
###############################################################
|
||||
""" Schauen, ob alles im gr<67>nen Bereich ist """
|
||||
return (line>=0) and (line<self.len)
|
||||
|
||||
|
||||
def IsEditable(self, line):
|
||||
###############################################################
|
||||
return self.text[self.GetLine(line)].editable
|
||||
|
||||
|
||||
def GetLine(self, line):
|
||||
###############################################################
|
||||
return self.lines[line]
|
||||
|
||||
|
||||
def GetTextLine(self, line):
|
||||
###############################################################
|
||||
""" Text holen """
|
||||
if self.IsLine(line):
|
||||
return self.text[self.GetLine(line)].text
|
||||
return ""
|
||||
|
||||
|
||||
def SetTextLine(self, line, text):
|
||||
###############################################################
|
||||
""" Nur den Text <20>ndern """
|
||||
if self.IsLine(line):
|
||||
l = self.GetLine(line)
|
||||
self.text[l].text = text
|
||||
#self.UpdateSyntax(l)
|
||||
self.OnUpdateHighlight(l)
|
||||
self.update = true
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def OnMouseClick(self, event):
|
||||
###############################################################
|
||||
"""
|
||||
Wenn es Click gemacht hat => Cursor setzen
|
||||
"""
|
||||
self.SetFocus()
|
||||
|
||||
self.cy = self.sy + (event.GetY() / self.fh)
|
||||
if self.cy >= self.len: self.cy =max(self.len -1, 0)
|
||||
linelen =len(self.text[self.GetLine(self.cy)].text)
|
||||
self.cx = self.sx + (event.GetX() / self.fw)
|
||||
# allow positioning right behind the last character
|
||||
if self.cx > linelen: self.cx =linelen
|
||||
if event.GetEventType() ==wxEVT_RIGHT_DOWN:
|
||||
self.update = true
|
||||
self.OnFold()
|
||||
self.UpdateView()
|
||||
|
||||
|
||||
def DrawCursor(self, dc = None):
|
||||
###############################################################
|
||||
"""
|
||||
Auch der Cursor mu<6D> ja irgendwie gezeichnet werden
|
||||
"""
|
||||
if not dc:
|
||||
dc = wxClientDC(self)
|
||||
|
||||
if (self.len)<self.cy: #-1 ?
|
||||
self.cy = self.len-1
|
||||
s = self.text[self.GetLine(self.cy)].text
|
||||
|
||||
x = self.cx - self.sx
|
||||
y = self.cy - self.sy
|
||||
self.DrawSimpleCursor(x, y, dc)
|
||||
|
||||
|
||||
def DrawSimpleCursor(self, xp, yp, dc = None, old=false):
|
||||
###############################################################
|
||||
"""
|
||||
Auch der Cursor mu<6D> ja irgendwie gezeichnet werden
|
||||
"""
|
||||
if not dc:
|
||||
dc = wxClientDC(self)
|
||||
|
||||
if old:
|
||||
xp = self.sco_x
|
||||
yp = self.sco_y
|
||||
|
||||
szx = self.fw
|
||||
szy = self.fh
|
||||
x = xp * szx
|
||||
y = yp * szy
|
||||
dc.Blit(x,y,szx,szy,dc,x,y,wxSRC_INVERT)
|
||||
self.sco_x = xp
|
||||
self.sco_y = yp
|
||||
|
||||
|
||||
def OnScroll(self, event):
|
||||
dir =event.GetOrientation()
|
||||
evt =event.GetEventType()
|
||||
if dir ==wxHORIZONTAL:
|
||||
if evt ==wxEVT_SCROLLWIN_LINEUP: self.sx =self.sx -1
|
||||
elif evt ==wxEVT_SCROLLWIN_LINEDOWN: self.sx =self.sx +1
|
||||
elif evt ==wxEVT_SCROLLWIN_PAGEUP: self.sx =self.sx -self.sw
|
||||
elif evt ==wxEVT_SCROLLWIN_PAGEDOWN: self.sx =self.sx +self.sw
|
||||
elif evt ==wxEVT_SCROLLWIN_TOP: self.sx =self.cx =0
|
||||
elif evt ==wxEVT_SCROLLWIN_BOTTOM:
|
||||
self.sx =self.max_linelength -self.sw
|
||||
self.cx =self.max_linelength
|
||||
else:
|
||||
self.sx =event.GetPosition()
|
||||
|
||||
if self.sx >(self.max_linelength -self.sw +1):
|
||||
self.sx =self.max_linelength -self.sw +1
|
||||
if self.sx <0: self.sx =0
|
||||
if self.cx >(self.sx +self.sw -1): self.cx =self.sx +self.sw -1
|
||||
if self.cx <self.sx: self.cx =self.sx
|
||||
|
||||
else:
|
||||
if evt ==wxEVT_SCROLLWIN_LINEUP: self.sy =self.sy -1
|
||||
elif evt ==wxEVT_SCROLLWIN_LINEDOWN: self.sy =self.sy +1
|
||||
elif evt ==wxEVT_SCROLLWIN_PAGEUP: self.sy =self.sy -self.sh
|
||||
elif evt ==wxEVT_SCROLLWIN_PAGEDOWN: self.sy =self.sy +self.sh
|
||||
elif evt ==wxEVT_SCROLLWIN_TOP: self.sy =self.cy =0
|
||||
elif evt ==wxEVT_SCROLLWIN_BOTTOM:
|
||||
self.sy =self.len -self.sh
|
||||
self.cy =self.len
|
||||
else:
|
||||
self.sy =event.GetPosition()
|
||||
|
||||
if self.sy >(self.len -self.sh +1):
|
||||
self.sy =self.len -self.sh +1
|
||||
if self.sy <0: self.sy =0
|
||||
if self.cy >(self.sy +self.sh -1): self.cy =self.sy +self.sh -1
|
||||
if self.cy <self.sy: self.cy =self.sy
|
||||
|
||||
self.UpdateView()
|
||||
|
||||
|
||||
def AdjustScrollbars(self):
|
||||
# there appears to be endless recursion:
|
||||
# SetScrollbars issue EvtPaint which calls UpdateView
|
||||
# which calls AdjustScrollbars
|
||||
if not self.in_scroll:
|
||||
self.in_scroll =TRUE
|
||||
self.SetScrollbars(self.fw, self.fh, self.max_linelength +1,
|
||||
# it seem to be a bug in scrollbars:
|
||||
# the scrollbar is hidden
|
||||
# even if current position >0
|
||||
max(self.len +1, self.sy +self.sh),
|
||||
self.sx, self.sy)
|
||||
self.osx, self.osy = self.sx, self.sy
|
||||
self.in_scroll =FALSE
|
||||
|
||||
|
||||
# adapts the output to what it should be
|
||||
def UpdateView(self, dc = None, doup=false):
|
||||
###############################################################
|
||||
"""
|
||||
Diese Routine wird immer dann aufgerufen, wenn
|
||||
sich etwas ver<65>ndert hat
|
||||
"""
|
||||
if self.inUpdate:
|
||||
return
|
||||
self.inUpdate = true
|
||||
|
||||
self.CalcLines()
|
||||
|
||||
if not dc:
|
||||
dc = wxClientDC(self)
|
||||
|
||||
self.bw,self.bh = self.GetSizeTuple()
|
||||
self.sw = self.bw / self.fw
|
||||
self.sh = self.bh / self.fh
|
||||
|
||||
if self.cy<self.sy:
|
||||
self.sy = self.cy
|
||||
elif self.cy>(self.sy+self.sh-1):
|
||||
self.sy = self.cy-self.sh+1
|
||||
|
||||
if self.cx<self.sx:
|
||||
self.sx = self.cx
|
||||
elif self.cx>(self.sx+self.sw-1):
|
||||
self.sx = self.cx-self.sw+1
|
||||
|
||||
# left line? change syntax!
|
||||
if self.ocy!=self.cy:
|
||||
self.OnUpdateSyntax(self.ocy)
|
||||
self.ocy = self.cy
|
||||
|
||||
# alles beim alten
|
||||
if self.osx != self.sx or self.osy != self.sy:
|
||||
self.AdjustScrollbars()
|
||||
|
||||
self.DrawSimpleCursor(0,0,dc, true)
|
||||
# [als] i don't really understand how the following condition works
|
||||
#if self.update or doup:
|
||||
self.Draw(dc)
|
||||
# self.update = false
|
||||
#else:
|
||||
# self.DrawCursor(dc)
|
||||
|
||||
self.o_cx = self.cx
|
||||
self.o_cy = self.cy
|
||||
self.o_sx = self.sx
|
||||
self.o_sy = self.sy
|
||||
self.o_line = self.line
|
||||
self.inUpdate = false
|
||||
|
||||
|
||||
|
||||
|
||||
def DrawEditText(self, t, x, y, dc = None):
|
||||
###############################################################
|
||||
""" Einfache Hilfsroutine um Text zu schreiben
|
||||
"""
|
||||
if not dc:
|
||||
dc = wxClientDC(self)
|
||||
dc.SetFont(self.font)
|
||||
dc.DrawText(t, x * self.fw, y * self.fh)
|
||||
|
||||
|
||||
def DrawLine(self, line, dc=None):
|
||||
###############################################################
|
||||
"""
|
||||
Hier wird einfach die Ansicht der ganzen Seite
|
||||
wiederhergestellt.
|
||||
!!! Kann modifiziert werden !!!
|
||||
"""
|
||||
|
||||
if not dc:
|
||||
dc = wxClientDC(self)
|
||||
|
||||
dc.SetBackgroundMode(wxSOLID)
|
||||
dc.SetTextBackground(self.bcol)
|
||||
dc.SetTextForeground(self.fcol)
|
||||
#dc.Clear()
|
||||
|
||||
# delimiter
|
||||
ll = self.sx
|
||||
lr = self.sx + self.sw
|
||||
y = line - self.sy
|
||||
|
||||
# text + syntax
|
||||
if self.IsLine(line):
|
||||
l = self.GetLine(line)
|
||||
t = self.text[l].text
|
||||
syn = self.text[l].syntax
|
||||
|
||||
if not self.text[l].editable:
|
||||
dc.SetTextBackground(self.nedcol)
|
||||
else:
|
||||
dc.SetTextBackground(self.bcol)
|
||||
|
||||
dc.SetTextForeground(self.fcol)
|
||||
|
||||
pos = ll
|
||||
for h in syn:
|
||||
xp, col = h
|
||||
if xp>=ll:
|
||||
self.DrawEditText(t[pos:xp], (pos-ll), y, dc)
|
||||
pos = xp
|
||||
dc.SetTextForeground(self.ftab[col])
|
||||
self.DrawEditText(t[pos:], (pos-ll), y, dc)
|
||||
|
||||
|
||||
def Draw(self, odc=None):
|
||||
###############################################################
|
||||
"""
|
||||
Hier wird einfach die Ansicht der ganzen Seite
|
||||
wiederhergestellt.
|
||||
!!! Kann modifiziert werden !!!
|
||||
"""
|
||||
|
||||
if not odc:
|
||||
odc = wxClientDC(self)
|
||||
|
||||
dc = self.mdc
|
||||
dc.SelectObject(wxEmptyBitmap(self.bw,self.bh))
|
||||
dc.SetBackgroundMode(wxSOLID)
|
||||
dc.SetTextBackground(self.bcol)
|
||||
dc.SetTextForeground(self.fcol)
|
||||
dc.Clear()
|
||||
for line in range(self.sy, self.sy + self.sh): self.DrawLine(line, dc)
|
||||
odc.Blit(0,0,self.bw,self.bh,dc,0,0,wxCOPY)
|
||||
self.DrawCursor(odc)
|
||||
|
||||
|
||||
def cVert(self, num):
|
||||
###############################################################
|
||||
""" Vertikale Cursorverschiebung
|
||||
"""
|
||||
cy = self.cy + num
|
||||
if cy <0: cy =0
|
||||
elif cy >(self.len -1): cy =self.len -1
|
||||
# scroll when edge hit
|
||||
if cy >(self.sy +self.sh -1): self.sy =cy -self.sh +1
|
||||
elif cy <self.sy: self.sy =cy
|
||||
self.cy =cy
|
||||
# disallow positioning behind the end of the line
|
||||
linelen =len(self.text[self.GetLine(cy)].text)
|
||||
if self.cx >linelen: self.cx =linelen
|
||||
|
||||
|
||||
def cHoriz(self, num):
|
||||
###############################################################
|
||||
""" Horizontale Cursorverschiebung
|
||||
"""
|
||||
cx = self.cx + num
|
||||
linelen =len(self.text[self.GetLine(self.cy)].text)
|
||||
if cx <0: cx =0
|
||||
elif cx >linelen: cx =linelen
|
||||
# scroll when edge hit
|
||||
if cx >(self.sx +self.sw -2): self.sx =cx -self.sw +2
|
||||
elif cx <self.sx: self.sx =cx
|
||||
self.cx =cx
|
||||
|
||||
|
||||
def InsertText(self, text):
|
||||
###############################################################
|
||||
"""
|
||||
Simple Routine um Text - auch <20>ber mehrere
|
||||
Zeilen - einzuf<75>gen
|
||||
"""
|
||||
|
||||
if self.IsEditable(self.cy):
|
||||
tis = split(text, "\n")
|
||||
|
||||
t = self.GetTextLine(self.cy)
|
||||
|
||||
if len(tis)==1:
|
||||
t = t[:self.cx] + text + t[self.cx:]
|
||||
self.SetTextLine(self.cy, t)
|
||||
self.cHoriz(len(text))
|
||||
else:
|
||||
rest = t[self.cx:]
|
||||
t = t[:self.cx] + tis[0]
|
||||
self.SetTextLine(self.cy, t)
|
||||
for i in range(1,len(tis)):
|
||||
self.text.insert(self.GetLine(self.cy)+1, Line())
|
||||
self.lines.insert(self.cy+1,self.GetLine(self.cy)+1)
|
||||
self.cVert(+1)
|
||||
self.SetTextLine(self.cy, tis[i])
|
||||
t = self.GetTextLine(self.cy)
|
||||
self.cx = len(t)
|
||||
t = t + rest
|
||||
self.SetTextLine(self.cy, t)
|
||||
self.update = true
|
||||
#self.UpdateView()
|
||||
|
||||
#-----------------------------------------------------------------------------------------
|
||||
|
||||
def RemoveLine(self, line):
|
||||
pass
|
||||
|
||||
|
||||
def OnChar(self, event):
|
||||
###############################################################
|
||||
"""
|
||||
Wenn eine Taste gedr<64>ckt wird,
|
||||
kann an dieser Stelle die Auswertung stattfinden
|
||||
"""
|
||||
|
||||
# get code
|
||||
key = event.KeyCode()
|
||||
|
||||
# if event.ControlDown:
|
||||
# if chr(key)=="k":
|
||||
# print "weg"
|
||||
|
||||
|
||||
# movements
|
||||
if key==WXK_DOWN:
|
||||
self.cVert(+1)
|
||||
elif key==WXK_UP:
|
||||
self.cVert(-1)
|
||||
elif key==WXK_LEFT:
|
||||
self.cHoriz(-1)
|
||||
elif key==WXK_RIGHT:
|
||||
self.cHoriz(+1)
|
||||
|
||||
elif key==WXK_NEXT:
|
||||
self.cVert(self.sh)
|
||||
elif key==WXK_PRIOR:
|
||||
self.cVert(-self.sh)
|
||||
|
||||
elif key==WXK_HOME:
|
||||
self.cx = 0
|
||||
elif key==WXK_END:
|
||||
self.cx = len(self.GetTextLine(self.cy))
|
||||
|
||||
elif key==WXK_BACK:
|
||||
t = self.GetTextLine(self.cy)
|
||||
if self.cx>0:
|
||||
t = t[:self.cx-1] + t[self.cx:]
|
||||
self.SetTextLine(self.cy, t)
|
||||
self.cHoriz(-1)
|
||||
|
||||
elif key==WXK_DELETE:
|
||||
t = self.GetTextLine(self.cy)
|
||||
if self.cx<len(t):
|
||||
t = t[:self.cx] + t[self.cx+1:]
|
||||
self.SetTextLine(self.cy, t)
|
||||
|
||||
elif key==WXK_RETURN:
|
||||
self.InsertText("\n")
|
||||
|
||||
elif key==WXK_TAB:
|
||||
self.OnTabulator(event)
|
||||
|
||||
# clipboard (buggy)
|
||||
elif key==WXK_F10:
|
||||
if wxTheClipboard.Open():
|
||||
data = wxTheClipboard.GetData()
|
||||
wxTheClipboard.Close()
|
||||
print data
|
||||
|
||||
# folding (buggy)
|
||||
elif key==WXK_F12:
|
||||
self.update = true
|
||||
self.OnFold()
|
||||
|
||||
# regular ascii
|
||||
elif (key>31) and (key<256):
|
||||
self.InsertText(chr(key))
|
||||
|
||||
self.UpdateView()
|
||||
return 0
|
||||
|
||||
|
||||
def OnPaint(self, event):
|
||||
dc = wxPaintDC(self)
|
||||
self.bw,self.bh = self.GetSizeTuple()
|
||||
self.UpdateView(dc, true)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------------------
|
||||
|
||||
def GetIndent(self, line):
|
||||
p = 0
|
||||
for c in line:
|
||||
if c==" ": p = p + 1
|
||||
elif c=="\t": p =(p /self.tabsize +1) *self.tabsize
|
||||
else: break
|
||||
return p
|
||||
|
||||
|
||||
def Goto(self, pos):
|
||||
self.cVert(pos-self.cy-1)
|
||||
self.UpdateView()
|
||||
|
||||
# --------------------------------------------------------
|
||||
|
||||
# to be overloaded
|
||||
def OnUpdateHighlight(self, line = -1):
|
||||
pass
|
||||
|
||||
def OnUpdateSyntax(self, line = -1):
|
||||
pass
|
||||
|
||||
def OnTabulator(self, event):
|
||||
pass
|
||||
|
||||
def OnInit(self):
|
||||
pass
|
||||
|
||||
def OnFold(self):
|
||||
pass
|
||||
|
211
wxPython/wxPython/lib/editor/py_editor.py
Normal file
211
wxPython/wxPython/lib/editor/py_editor.py
Normal file
@@ -0,0 +1,211 @@
|
||||
# (C)opyright by Dirk Holtwick, 1999
|
||||
# ----------------------------------
|
||||
# holtwick@spirito.de
|
||||
# http://www.spirito.de/pyde
|
||||
|
||||
from editor import *
|
||||
from string import *
|
||||
from keyword import *
|
||||
from tokenizer import *
|
||||
|
||||
"""
|
||||
This module will be loaded by the main
|
||||
window. It implements some methods that
|
||||
are typical for Python sources.
|
||||
"""
|
||||
|
||||
class wxPyEditor(wxEditor):
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __init__(self, parent, id,
|
||||
pos=wxDefaultPosition, size=wxDefaultSize, style=0):
|
||||
wxEditor.__init__(self, parent, id, pos, size, style)
|
||||
self.SetFontTab([
|
||||
wxNamedColour('black'),
|
||||
wxNamedColour('blue'),
|
||||
wxNamedColour('red'),
|
||||
wxNamedColour('darkgreen'),
|
||||
wxNamedColour('brown')
|
||||
])
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def OnUpdateHighlight(self, line = -1):
|
||||
if line>=0:
|
||||
t = self.text[line].text
|
||||
syn = []
|
||||
|
||||
toks = Tokenizer(t).tokens()
|
||||
for type, string, begin, end in toks:
|
||||
if type == "KEY":
|
||||
syn.append((begin, 1))
|
||||
syn.append((end, 0))
|
||||
elif type == "COMMENT":
|
||||
syn.append((begin, 2))
|
||||
elif type == "STRING":
|
||||
syn.append((begin, 3))
|
||||
syn.append((end, 0))
|
||||
elif type == "NUMBER":
|
||||
syn.append((begin, 4))
|
||||
syn.append((end, 0))
|
||||
elif type == "NAME":
|
||||
if string=="self":
|
||||
syn.append((begin, 4))
|
||||
syn.append((end, 0))
|
||||
else:
|
||||
pass
|
||||
self.text[line].syntax = syn
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def OnUpdateSyntax(self, line = -1):
|
||||
if line>=0:
|
||||
"""
|
||||
tx, syn, m = self.text[line]
|
||||
pre = 0
|
||||
for i in range(0,len(tx)):
|
||||
if tx[i] != " ":
|
||||
pre = i
|
||||
break
|
||||
t = tx[pre:]
|
||||
|
||||
t = Tokenizer(t).line()
|
||||
|
||||
t = tx[:pre] + t
|
||||
self.text[line] = t, syn, m
|
||||
"""
|
||||
self.OnUpdateHighlight(line)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def OnTabulator(self, event):
|
||||
add = +1
|
||||
if event.ShiftDown():
|
||||
add = -1
|
||||
t = self.GetTextLine(self.cy)
|
||||
if strip(t):
|
||||
indent = self.GetIndent(t)
|
||||
# print indent
|
||||
t = t[indent:]
|
||||
tabs = indent / self.tabsize
|
||||
# for i in range(0,tabs+add):
|
||||
t = (" " * 4 * (tabs+add)) + t
|
||||
self.SetTextLine(self.cy, t)
|
||||
elif add>0:
|
||||
self.InsertText(" ")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def FindQuote(self, lineno, quote_type='"""', direction=1):
|
||||
"""find line containing the matching quote"""
|
||||
l =lineno +direction
|
||||
while (l < len(self.text)-1) and (l >= 0):
|
||||
if find(self.text[l].text, quote_type) >=0: return l
|
||||
l =l +direction
|
||||
return None
|
||||
|
||||
def FindNextLine(self, lineno, direction=1):
|
||||
"""get the next line of code (skipping comment lines and empty lines)"""
|
||||
l =lineno +direction
|
||||
while (l < len(self.text)-1) and (l >= 0):
|
||||
str =lstrip(self.text[l].text)
|
||||
if (len(str) >0) and (str[0] !="#"): return l
|
||||
l =l +direction
|
||||
return None
|
||||
|
||||
def Fold(self):
|
||||
l = self.GetLine(self.cy)
|
||||
line = self.text[l]
|
||||
t = line.text
|
||||
|
||||
# fold ...
|
||||
if line.editable:
|
||||
|
||||
# 3*quotes
|
||||
qpos =find(t, '"""')
|
||||
if qpos >=0: qtype ='"""'
|
||||
else:
|
||||
qpos =find(t, "'''")
|
||||
if qpos >=0: qtype ="'''"
|
||||
|
||||
if (qpos >=0) and (find(t[qpos+3:], qtype) <0):
|
||||
closing_quote =self.FindQuote(l, qtype)
|
||||
if closing_quote !=None:
|
||||
line.editable = not line.editable
|
||||
l =l +1
|
||||
while l <= closing_quote:
|
||||
self.text[l].visible =self.text[l].visible +1
|
||||
l =l +1
|
||||
|
||||
else: # try normal fold on leading whitespace
|
||||
lim = self.GetIndent(t)
|
||||
lnext =self.FindNextLine(l)
|
||||
if (lnext !=None) \
|
||||
and (self.GetIndent(self.text[lnext].text) >lim):
|
||||
line.editable =FALSE
|
||||
lstart =l +1
|
||||
l =self.FindNextLine(l)
|
||||
while (l !=None) \
|
||||
and (self.GetIndent(self.text[l].text) >lim):
|
||||
l =self.FindNextLine(l)
|
||||
if l ==None:
|
||||
# fold till the end
|
||||
l =len(self.text)
|
||||
for line in self.text[lstart:l]:
|
||||
line.visible =line.visible +1
|
||||
|
||||
# ... or unfold
|
||||
else:
|
||||
lim = line.visible + 1
|
||||
line.editable = not line.editable
|
||||
|
||||
l = l + 1
|
||||
line = self.text[l]
|
||||
while (l < (len(self.text) -1)) and (line.visible>=lim):
|
||||
line.visible = line.visible - 1
|
||||
l = l + 1
|
||||
line = self.text[l]
|
||||
|
||||
def FoldAll(self):
|
||||
self.CalcLines()
|
||||
self.cx = 0
|
||||
self.cy = len(self.lines) - 1
|
||||
prev_indent =0
|
||||
# following loop is exited in two cases:
|
||||
# when self.cy becomes 0 (topmost level is not folded by FoldAll)
|
||||
# or when FindNextLine() returns None (all remaining lines till
|
||||
# the beginning of the text are empty or comments)
|
||||
while self.cy:
|
||||
t = self.GetTextLine(self.cy)
|
||||
# indent-based folding
|
||||
indent =self.GetIndent(t)
|
||||
if indent <prev_indent:
|
||||
self.Fold()
|
||||
prev_indent =indent
|
||||
# triple-quote folding
|
||||
qpos =find(t, '"""')
|
||||
if qpos >=0: qtype ='"""'
|
||||
else:
|
||||
qpos =find(t, "'''")
|
||||
if qpos >=0: qtype ="'''"
|
||||
if (qpos >=0) and (find(t[qpos+3:], qtype) <0):
|
||||
closing_quote =self.FindQuote(self.cy, qtype, -1)
|
||||
if closing_quote !=None:
|
||||
# XXX potential bug: unmatched triple quotes
|
||||
self.cy =closing_quote
|
||||
self.Fold()
|
||||
self.cy =self.FindNextLine(self.cy, -1)
|
||||
if self.cy ==None: self.cy =0
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def OnFold(self):
|
||||
self.Fold()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def OnInit(self):
|
||||
#self.FoldAll()
|
||||
pass
|
||||
|
60
wxPython/wxPython/lib/editor/tokenizer.py
Normal file
60
wxPython/wxPython/lib/editor/tokenizer.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from tokenize import *
|
||||
from keyword import *
|
||||
from string import *
|
||||
|
||||
class Tokenizer:
|
||||
"""
|
||||
Simple class to create a list of token-tuples like:
|
||||
|
||||
(type, string, first, last)
|
||||
|
||||
Example:
|
||||
t = Tokenizer('def hallo(du): # juchee')
|
||||
print t.tokens()
|
||||
"""
|
||||
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
self.toks = []
|
||||
try:
|
||||
tokenize(self.readline, self.get)
|
||||
except TokenError:
|
||||
pass
|
||||
|
||||
def tokens(self):
|
||||
return self.toks
|
||||
|
||||
def get(self, type, string, begin, end, l):
|
||||
#print begin,end
|
||||
h1, b = begin
|
||||
h2, e = end
|
||||
tname = tok_name[type]
|
||||
if iskeyword(string):
|
||||
tname = "KEY"
|
||||
self.toks.append(tname, string, b, e)
|
||||
|
||||
def readline(self):
|
||||
t = self.text
|
||||
self.text = ""
|
||||
return t
|
||||
|
||||
def line(self):
|
||||
pre = ""
|
||||
out = ""
|
||||
for type, string, begin, end in self.toks:
|
||||
if (pre in ["NAME","KEY"]) and (not string in [".",",","("]):
|
||||
out = out + " "
|
||||
|
||||
if type in ["NAME","KEY"]:
|
||||
out = out + string
|
||||
elif type=="OP":
|
||||
if string in [",",":"]:
|
||||
out = out + string + " "
|
||||
else:
|
||||
out = out + string
|
||||
else:
|
||||
out = out + string
|
||||
pre = type
|
||||
return out
|
||||
|
||||
|
404
wxPython/wxPython/lib/filebrowsebutton.py
Normal file
404
wxPython/wxPython/lib/filebrowsebutton.py
Normal file
@@ -0,0 +1,404 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.filebrowsebutton
|
||||
# Purpose: Composite controls that provide a Browse button next to
|
||||
# either a wxTextCtrl or a wxComboBox. The Browse button
|
||||
# launches a wxFileDialog and loads the result into the
|
||||
# other control.
|
||||
#
|
||||
# Author: Mike Fletcher
|
||||
#
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 2000 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
from wxPython.wx import *
|
||||
import os
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class FileBrowseButton(wxPanel):
|
||||
""" A control to allow the user to type in a filename
|
||||
or browse with the standard file dialog to select file
|
||||
|
||||
__init__ (
|
||||
parent, id, pos, size -- passed directly to wxPanel initialisation
|
||||
style = wxTAB_TRAVERSAL -- passed directly to wxPanel initialisation
|
||||
labelText -- Text for label to left of text field
|
||||
buttonText -- Text for button which launches the file dialog
|
||||
toolTip -- Help text
|
||||
dialogTitle -- Title used in file dialog
|
||||
startDirectory -- Default directory for file dialog startup
|
||||
fileMask -- File mask (glob pattern, such as *.*) to use in file dialog
|
||||
fileMode -- wxOPEN or wxSAVE, indicates type of file dialog to use
|
||||
changeCallback -- callback receives all changes in value of control
|
||||
)
|
||||
GetValue() -- retrieve current value of text control
|
||||
SetValue(string) -- set current value of text control
|
||||
label -- pointer to internal label widget
|
||||
textControl -- pointer to internal text control
|
||||
browseButton -- pointer to button
|
||||
"""
|
||||
def __init__ (self, parent, id= -1,
|
||||
pos = wxDefaultPosition, size = wxDefaultSize,
|
||||
style = wxTAB_TRAVERSAL,
|
||||
labelText= "File Entry:",
|
||||
buttonText= "Browse",
|
||||
toolTip= "Type filename or click browse to choose file",
|
||||
# following are the values for a file dialog box
|
||||
dialogTitle = "Choose a file",
|
||||
startDirectory = ".",
|
||||
initialValue = "",
|
||||
fileMask = "*.*",
|
||||
fileMode = wxOPEN,
|
||||
# callback for when value changes (optional)
|
||||
changeCallback= lambda x:x
|
||||
):
|
||||
# store variables
|
||||
self.labelText = labelText
|
||||
self.buttonText = buttonText
|
||||
self.toolTip = toolTip
|
||||
self.dialogTitle = dialogTitle
|
||||
self.startDirectory = startDirectory
|
||||
self.initialValue = initialValue
|
||||
self.fileMask = fileMask
|
||||
self.fileMode = fileMode
|
||||
self.changeCallback = changeCallback
|
||||
|
||||
# create the dialog
|
||||
self.createDialog(parent, id, pos, size, style )
|
||||
# Setting a value causes the changeCallback to be called.
|
||||
# In this case that would be before the return of the
|
||||
# constructor. Not good. So a default value on
|
||||
# SetValue is used to disable the callback
|
||||
self.SetValue( initialValue, 0)
|
||||
|
||||
def createDialog( self, parent, id, pos, size, style ):
|
||||
"""Setup the graphic representation of the dialog"""
|
||||
wxPanel.__init__ (self, parent, id, pos, size, style)
|
||||
|
||||
box = wxBoxSizer(wxHORIZONTAL)
|
||||
|
||||
self.label = self.createLabel( )
|
||||
box.Add( self.label, 0, wxCENTER )
|
||||
|
||||
self.textControl = self.createTextControl()
|
||||
box.Add( self.textControl, 1, wxLEFT|wxCENTER, 5)
|
||||
|
||||
self.browseButton = self.createBrowseButton()
|
||||
box.Add( self.browseButton, 0, wxCENTER)
|
||||
|
||||
# add a border around the whole thing and resize the panel to fit
|
||||
outsidebox = wxBoxSizer(wxVERTICAL)
|
||||
outsidebox.Add(box, 1, wxEXPAND|wxALL, 3)
|
||||
outsidebox.Fit(self)
|
||||
|
||||
self.SetAutoLayout(true)
|
||||
self.SetSizer( outsidebox )
|
||||
self.Layout()
|
||||
if size.width != -1 or size.height != -1:
|
||||
self.SetSize(size)
|
||||
|
||||
def createLabel( self ):
|
||||
"""Create the label/caption"""
|
||||
label = wxStaticText(self, -1, self.labelText, style =wxALIGN_RIGHT )
|
||||
font = label.GetFont()
|
||||
w, h, d, e = self.GetFullTextExtent(self.labelText, font)
|
||||
label.SetSize(wxSize(w+5, h))
|
||||
return label
|
||||
|
||||
def createTextControl( self):
|
||||
"""Create the text control"""
|
||||
ID = wxNewId()
|
||||
textControl = wxTextCtrl(self, ID)
|
||||
textControl.SetToolTipString( self.toolTip )
|
||||
if self.changeCallback:
|
||||
EVT_TEXT(textControl, ID, self.changeCallback)
|
||||
EVT_COMBOBOX(textControl, ID, self.changeCallback)
|
||||
return textControl
|
||||
|
||||
def createBrowseButton( self):
|
||||
"""Create the browse-button control"""
|
||||
ID = wxNewId()
|
||||
button =wxButton(self, ID, self.buttonText)
|
||||
button.SetToolTipString( self.toolTip )
|
||||
EVT_BUTTON(button, ID, self.OnBrowse)
|
||||
return button
|
||||
|
||||
def OnBrowse (self, event = None):
|
||||
""" Going to browse for file... """
|
||||
current = self.GetValue ()
|
||||
directory = os.path.split(current)
|
||||
if os.path.isdir( current):
|
||||
directory = current
|
||||
elif directory and os.path.isdir( directory[0] ):
|
||||
directory = directory [0]
|
||||
else:
|
||||
directory = self.startDirectory
|
||||
dlg = wxFileDialog(self, self.dialogTitle, directory, current, self.fileMask, self.fileMode)
|
||||
if dlg.ShowModal() == wxID_OK:
|
||||
self.SetValue (dlg.GetPath())
|
||||
dlg.Destroy()
|
||||
|
||||
def GetValue (self):
|
||||
""" Convenient access to text control value """
|
||||
return self.textControl.GetValue ()
|
||||
|
||||
def SetValue (self, value, callBack=1):
|
||||
""" Convenient setting of text control value """
|
||||
# Removed the return from here because SetValue doesn't return anything.
|
||||
self.textControl.SetValue (value)
|
||||
|
||||
def Enable (self, value):
|
||||
""" Convenient enabling/disabling of entire control """
|
||||
self.label.Enable (value)
|
||||
self.textControl.Enable (value)
|
||||
return self.browseButton.Enable (value)
|
||||
|
||||
def GetLabel( self ):
|
||||
""" Retrieve the label's current text """
|
||||
return self.label.GetLabel()
|
||||
|
||||
def SetLabel( self, value ):
|
||||
""" Set the label's current text """
|
||||
rvalue = self.label.SetLabel( value )
|
||||
self.Refresh( true )
|
||||
return rvalue
|
||||
|
||||
|
||||
|
||||
class FileBrowseButtonWithHistory( FileBrowseButton ):
|
||||
""" with following additions:
|
||||
__init__(..., history=None)
|
||||
|
||||
history -- optional list of paths for initial history drop-down
|
||||
(must be passed by name, not a positional argument)
|
||||
If history is callable it will must return a list used
|
||||
for the history drop-down
|
||||
changeCallback -- as for FileBrowseButton, but with a work-around
|
||||
for win32 systems which don't appear to create EVT_COMBOBOX
|
||||
events properly. There is a (slight) chance that this work-around
|
||||
will cause some systems to create two events for each Combobox
|
||||
selection. If you discover this condition, please report it!
|
||||
As for a FileBrowseButton.__init__ otherwise.
|
||||
GetHistoryControl()
|
||||
Return reference to the control which implements interfaces
|
||||
required for manipulating the history list. See GetHistoryControl
|
||||
documentation for description of what that interface is.
|
||||
GetHistory()
|
||||
Return current history list
|
||||
SetHistory( value=(), selectionIndex = None )
|
||||
Set current history list, if selectionIndex is not None, select that index
|
||||
"""
|
||||
def __init__( self, *arguments, **namedarguments):
|
||||
self.history = namedarguments.get( "history" )
|
||||
if self.history:
|
||||
del namedarguments["history"]
|
||||
|
||||
self.historyCallBack=None
|
||||
if callable(self.history):
|
||||
self.historyCallBack=self.history
|
||||
self.history=None
|
||||
apply( FileBrowseButton.__init__, ( self,)+arguments, namedarguments)
|
||||
|
||||
def createTextControl( self):
|
||||
"""Create the text control"""
|
||||
ID = wxNewId()
|
||||
textControl = wxComboBox(self, ID, style = wxCB_DROPDOWN )
|
||||
textControl.SetToolTipString( self.toolTip )
|
||||
EVT_SET_FOCUS(textControl, self.OnSetFocus)
|
||||
if self.changeCallback:
|
||||
EVT_TEXT(textControl, ID, self.changeCallback)
|
||||
EVT_COMBOBOX(textControl, ID, self.changeCallback)
|
||||
if self.history:
|
||||
history=self.history
|
||||
self.history=None
|
||||
self.SetHistory( history, control=textControl)
|
||||
return textControl
|
||||
|
||||
def GetHistoryControl( self ):
|
||||
"""Return a pointer to the control which provides (at least)
|
||||
the following methods for manipulating the history list.:
|
||||
Append( item ) -- add item
|
||||
Clear() -- clear all items
|
||||
Delete( index ) -- 0-based index to delete from list
|
||||
SetSelection( index ) -- 0-based index to select in list
|
||||
Semantics of the methods follow those for the wxComboBox control
|
||||
"""
|
||||
return self.textControl
|
||||
|
||||
def SetHistory( self, value=(), selectionIndex = None, control=None ):
|
||||
"""Set the current history list"""
|
||||
if control is None:
|
||||
control = self.GetHistoryControl()
|
||||
if self.history == value:
|
||||
return
|
||||
self.history = value
|
||||
# Clear history values not the selected one.
|
||||
tempValue=control.GetValue()
|
||||
# clear previous values
|
||||
control.Clear()
|
||||
control.SetValue(tempValue)
|
||||
# walk through, appending new values
|
||||
for path in value:
|
||||
control.Append( path )
|
||||
if selectionIndex is not None:
|
||||
control.SetSelection( selectionIndex )
|
||||
|
||||
def GetHistory( self ):
|
||||
"""Return the current history list"""
|
||||
if self.historyCallBack != None:
|
||||
return self.historyCallBack()
|
||||
else:
|
||||
return list( self.history )
|
||||
|
||||
def OnSetFocus(self, event):
|
||||
"""When the history scroll is selected, update the history"""
|
||||
if self.historyCallBack != None:
|
||||
self.SetHistory( self.historyCallBack(), control=self.textControl)
|
||||
event.Skip()
|
||||
|
||||
if wxPlatform == "__WXMSW__":
|
||||
def SetValue (self, value, callBack=1):
|
||||
""" Convenient setting of text control value, works
|
||||
around limitation of wxComboBox """
|
||||
# Removed the return from here because SetValue doesn't return anything.
|
||||
self.textControl.SetValue (value)
|
||||
# Hack to call an event handler
|
||||
class LocalEvent:
|
||||
def __init__(self, string):
|
||||
self._string=string
|
||||
def GetString(self):
|
||||
return self._string
|
||||
if callBack==1:
|
||||
# The callback wasn't being called when SetValue was used ??
|
||||
# So added this explicit call to it
|
||||
self.changeCallback(LocalEvent(value))
|
||||
|
||||
|
||||
class DirBrowseButton(FileBrowseButton):
|
||||
def __init__(self, parent, id = -1,
|
||||
pos = wxDefaultPosition, size = wxDefaultSize,
|
||||
style = wxTAB_TRAVERSAL,
|
||||
labelText = 'Select a directory:',
|
||||
buttonText = 'Browse',
|
||||
toolTip = 'Type directory name or browse to select',
|
||||
dialogTitle = '',
|
||||
startDirectory = '.',
|
||||
changeCallback = None,
|
||||
dialogClass = wxDirDialog):
|
||||
FileBrowseButton.__init__(self, parent, id, pos, size, style,
|
||||
labelText, buttonText, toolTip,
|
||||
dialogTitle, startDirectory,
|
||||
changeCallback = changeCallback)
|
||||
#
|
||||
self._dirDialog = dialogClass(self,
|
||||
message = dialogTitle,
|
||||
defaultPath = startDirectory)
|
||||
#
|
||||
def OnBrowse(self, ev = None):
|
||||
dialog = self._dirDialog
|
||||
if dialog.ShowModal() == wxID_OK:
|
||||
self.SetValue(dialog.GetPath())
|
||||
#
|
||||
def __del__(self):
|
||||
if self.__dict__.has_key('_dirDialog'):
|
||||
self._dirDialog.Destroy()
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
#from skeletonbuilder import rulesfile
|
||||
class SimpleCallback:
|
||||
def __init__( self, tag ):
|
||||
self.tag = tag
|
||||
def __call__( self, event ):
|
||||
print self.tag, event.GetString()
|
||||
class DemoFrame( wxFrame ):
|
||||
def __init__(self, parent):
|
||||
wxFrame.__init__(self, parent, 2400, "File entry with browse", size=(500,260) )
|
||||
EVT_CLOSE(self, self.OnCloseWindow)
|
||||
panel = wxPanel (self,-1)
|
||||
innerbox = wxBoxSizer(wxVERTICAL)
|
||||
control = FileBrowseButton(
|
||||
panel,
|
||||
initialValue = "z:\\temp",
|
||||
)
|
||||
innerbox.Add( control, 0, wxEXPAND )
|
||||
middlecontrol = FileBrowseButtonWithHistory(
|
||||
panel,
|
||||
labelText = "With History",
|
||||
initialValue = "d:\\temp",
|
||||
history = ["c:\\temp", "c:\\tmp", "r:\\temp","z:\\temp"],
|
||||
changeCallback= SimpleCallback( "With History" ),
|
||||
)
|
||||
innerbox.Add( middlecontrol, 0, wxEXPAND )
|
||||
middlecontrol = FileBrowseButtonWithHistory(
|
||||
panel,
|
||||
labelText = "History callback",
|
||||
initialValue = "d:\\temp",
|
||||
history = self.historyCallBack,
|
||||
changeCallback= SimpleCallback( "History callback" ),
|
||||
)
|
||||
innerbox.Add( middlecontrol, 0, wxEXPAND )
|
||||
self.bottomcontrol = control = FileBrowseButton(
|
||||
panel,
|
||||
labelText = "With Callback",
|
||||
style = wxSUNKEN_BORDER|wxCLIP_CHILDREN ,
|
||||
changeCallback= SimpleCallback( "With Callback" ),
|
||||
)
|
||||
innerbox.Add( control, 0, wxEXPAND)
|
||||
self.bottommostcontrol = control = DirBrowseButton(
|
||||
panel,
|
||||
labelText = "Simple dir browse button",
|
||||
style = wxSUNKEN_BORDER|wxCLIP_CHILDREN)
|
||||
innerbox.Add( control, 0, wxEXPAND)
|
||||
ID = wxNewId()
|
||||
innerbox.Add( wxButton( panel, ID,"Change Label", ), 1, wxEXPAND)
|
||||
EVT_BUTTON( self, ID, self.OnChangeLabel )
|
||||
ID = wxNewId()
|
||||
innerbox.Add( wxButton( panel, ID,"Change Value", ), 1, wxEXPAND)
|
||||
EVT_BUTTON( self, ID, self.OnChangeValue )
|
||||
panel.SetAutoLayout(true)
|
||||
panel.SetSizer( innerbox )
|
||||
self.history={"c:\\temp":1, "c:\\tmp":1, "r:\\temp":1,"z:\\temp":1}
|
||||
|
||||
def historyCallBack(self):
|
||||
keys=self.history.keys()
|
||||
keys.sort()
|
||||
return keys
|
||||
|
||||
def OnFileNameChangedHistory (self, event):
|
||||
self.history[event.GetString ()]=1
|
||||
|
||||
def OnCloseMe(self, event):
|
||||
self.Close(true)
|
||||
def OnChangeLabel( self, event ):
|
||||
self.bottomcontrol.SetLabel( "Label Updated" )
|
||||
def OnChangeValue( self, event ):
|
||||
self.bottomcontrol.SetValue( "r:\\somewhere\\over\\the\\rainbow.htm" )
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
class DemoApp(wxApp):
|
||||
def OnInit(self):
|
||||
wxImage_AddHandler(wxJPEGHandler())
|
||||
wxImage_AddHandler(wxPNGHandler())
|
||||
wxImage_AddHandler(wxGIFHandler())
|
||||
frame = DemoFrame(NULL)
|
||||
#frame = RulesPanel(NULL )
|
||||
frame.Show(true)
|
||||
self.SetTopWindow(frame)
|
||||
return true
|
||||
|
||||
def test( ):
|
||||
app = DemoApp(0)
|
||||
app.MainLoop()
|
||||
print 'Creating dialog'
|
||||
test( )
|
||||
|
||||
|
||||
|
276
wxPython/wxPython/lib/floatbar.py
Normal file
276
wxPython/wxPython/lib/floatbar.py
Normal file
@@ -0,0 +1,276 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: floatbar.py
|
||||
# Purpose: Contains floating toolbar class
|
||||
#
|
||||
# Author: Bryn Keller
|
||||
#
|
||||
# Created: 10/4/99
|
||||
#----------------------------------------------------------------------------
|
||||
from wxPython.wx import *
|
||||
|
||||
if wxPlatform == '__WXGTK__':
|
||||
#
|
||||
# For wxGTK all we have to do is set the wxTB_DOCKABLE flag
|
||||
#
|
||||
class wxFloatBar(wxToolBar):
|
||||
def __init__(self, parent, ID,
|
||||
pos = wxDefaultPosition,
|
||||
size = wxDefaultSize,
|
||||
style = 0,
|
||||
name = 'toolbar'):
|
||||
wxToolBar.__init__(self, parent, ID, pos, size,
|
||||
style|wxTB_DOCKABLE, name)
|
||||
|
||||
# these other methods just become no-ops
|
||||
def SetFloatable(self, float):
|
||||
pass
|
||||
|
||||
def IsFloating(self):
|
||||
return 1
|
||||
|
||||
def GetTitle(self):
|
||||
return ""
|
||||
|
||||
|
||||
def SetTitle(self, title):
|
||||
pass
|
||||
|
||||
else:
|
||||
_DOCKTHRESHOLD = 25
|
||||
|
||||
class wxFloatBar(wxToolBar):
|
||||
"""
|
||||
wxToolBar subclass which can be dragged off its frame and later
|
||||
replaced there. Drag on the toolbar to release it, close it like
|
||||
a normal window to make it return to its original
|
||||
position. Programmatically, call SetFloatable(true) and then
|
||||
Float(true) to float, Float(false) to dock.
|
||||
"""
|
||||
|
||||
def __init__(self,*_args,**_kwargs):
|
||||
"""
|
||||
In addition to the usual arguments, wxFloatBar accepts keyword
|
||||
args of: title(string): the title that should appear on the
|
||||
toolbar's frame when it is floating. floatable(bool): whether
|
||||
user actions (i.e., dragging) can float the toolbar or not.
|
||||
"""
|
||||
args = (self,) + _args
|
||||
apply(wxToolBar.__init__, args, _kwargs)
|
||||
if _kwargs.has_key('floatable'):
|
||||
self.floatable = _kwargs['floatable']
|
||||
assert type(self.floatable) == type(0)
|
||||
else:
|
||||
self.floatable = 0
|
||||
self.floating = 0
|
||||
if _kwargs.has_key('title'):
|
||||
self.title = _kwargs['title']
|
||||
assert type(self.title) == type("")
|
||||
else:
|
||||
self.title = ""
|
||||
EVT_MOUSE_EVENTS(self, self.OnMouse)
|
||||
self.parentframe = wxPyTypeCast(args[1], 'wxFrame')
|
||||
|
||||
|
||||
def IsFloatable(self):
|
||||
return self.floatable
|
||||
|
||||
|
||||
def SetFloatable(self, float):
|
||||
self.floatable = float
|
||||
#Find the size of a title bar.
|
||||
if not hasattr(self, 'titleheight'):
|
||||
test = wxMiniFrame(NULL, -1, "TEST")
|
||||
test.SetClientSize(wxSize(0,0))
|
||||
self.titleheight = test.GetSizeTuple()[1]
|
||||
test.Destroy()
|
||||
|
||||
|
||||
def IsFloating(self):
|
||||
return self.floating
|
||||
|
||||
|
||||
def Realize(self):
|
||||
wxToolBar.Realize(self)
|
||||
|
||||
|
||||
def GetTitle(self):
|
||||
return self.title
|
||||
|
||||
|
||||
def SetTitle(self, title):
|
||||
print 'SetTitle', title
|
||||
self.title = title
|
||||
if self.IsFloating():
|
||||
self.floatframe.SetTitle(self.title)
|
||||
|
||||
|
||||
## def GetHome(self):
|
||||
## """
|
||||
## Returns the frame which this toolbar will return to when
|
||||
## docked, or the parent if currently docked.
|
||||
## """
|
||||
## if hasattr(self, 'parentframe'):
|
||||
## return self.parentframe
|
||||
## else:
|
||||
## return wxPyTypeCast(self.GetParent(), 'wxFrame')
|
||||
|
||||
|
||||
## def SetHome(self, frame):
|
||||
## """
|
||||
## Called when docked, this will remove the toolbar from its
|
||||
## current frame and attach it to another. If called when
|
||||
## floating, it will dock to the frame specified when the toolbar
|
||||
## window is closed.
|
||||
## """
|
||||
## if self.IsFloating():
|
||||
## self.parentframe = frame
|
||||
## self.floatframe.Reparent(frame)
|
||||
## else:
|
||||
## parent = wxPyTypeCast(self.GetParent(), 'wxFrame')
|
||||
## self.Reparent(frame)
|
||||
## parent.SetToolBar(None)
|
||||
## size = parent.GetSize()
|
||||
## parent.SetSize(wxSize(0,0))
|
||||
## parent.SetSize(size)
|
||||
## frame.SetToolBar(self)
|
||||
## size = frame.GetSize()
|
||||
## frame.SetSize(wxSize(0,0))
|
||||
## frame.SetSize(size)
|
||||
|
||||
|
||||
def Float(self, bool):
|
||||
"Floats or docks the toolbar programmatically."
|
||||
if bool:
|
||||
self.parentframe = wxPyTypeCast(self.GetParent(), 'wxFrame')
|
||||
print self.title
|
||||
if self.title:
|
||||
useStyle = wxDEFAULT_FRAME_STYLE
|
||||
else:
|
||||
useStyle = wxTHICK_FRAME
|
||||
self.floatframe = wxMiniFrame(self.parentframe, -1, self.title,
|
||||
style = useStyle)
|
||||
|
||||
self.Reparent(self.floatframe)
|
||||
self.parentframe.SetToolBar(None)
|
||||
self.floating = 1
|
||||
psize = self.parentframe.GetSize()
|
||||
self.parentframe.SetSize(wxSize(0,0))
|
||||
self.parentframe.SetSize(psize)
|
||||
self.floatframe.SetToolBar(self)
|
||||
self.oldcolor = self.GetBackgroundColour()
|
||||
|
||||
w = psize.width
|
||||
h = self.GetSize().height
|
||||
if self.title:
|
||||
h = h + self.titleheight
|
||||
self.floatframe.SetSize(wxSize(w,h))
|
||||
self.floatframe.SetClientSize(self.GetSize())
|
||||
newpos = self.parentframe.GetPosition()
|
||||
newpos.y = newpos.y + _DOCKTHRESHOLD * 2
|
||||
self.floatframe.SetPosition(newpos)
|
||||
self.floatframe.Show(true)
|
||||
|
||||
EVT_CLOSE(self.floatframe, self.OnDock)
|
||||
#EVT_MOVE(self.floatframe, self.OnMove)
|
||||
|
||||
else:
|
||||
self.Reparent(self.parentframe)
|
||||
self.parentframe.SetToolBar(self)
|
||||
self.floating = 0
|
||||
self.floatframe.SetToolBar(None)
|
||||
self.floatframe.Destroy()
|
||||
size = self.parentframe.GetSize()
|
||||
self.parentframe.SetSize(wxSize(0,0))
|
||||
self.parentframe.SetSize(size)
|
||||
self.SetBackgroundColour(self.oldcolor)
|
||||
|
||||
|
||||
def OnDock(self, e):
|
||||
self.Float(0)
|
||||
if hasattr(self, 'oldpos'):
|
||||
del self.oldpos
|
||||
|
||||
|
||||
def OnMove(self, e):
|
||||
homepos = self.parentframe.ClientToScreen(wxPoint(0,0))
|
||||
floatpos = self.floatframe.GetPosition()
|
||||
if (abs(homepos.x - floatpos.x) < _DOCKTHRESHOLD and
|
||||
abs(homepos.y - floatpos.y) < _DOCKTHRESHOLD):
|
||||
self.Float(0)
|
||||
#homepos = self.parentframe.GetPositionTuple()
|
||||
#homepos = homepos[0], homepos[1] + self.titleheight
|
||||
#floatpos = self.floatframe.GetPositionTuple()
|
||||
#if abs(homepos[0] - floatpos[0]) < 35 and abs(homepos[1] - floatpos[1]) < 35:
|
||||
# self._SetFauxBarVisible(true)
|
||||
#else:
|
||||
# self._SetFauxBarVisible(false)
|
||||
|
||||
|
||||
def OnMouse(self, e):
|
||||
if not self.IsFloatable():
|
||||
e.Skip()
|
||||
return
|
||||
|
||||
if e.ButtonDClick(1) or e.ButtonDClick(2) or e.ButtonDClick(3) or e.ButtonDown() or e.ButtonUp():
|
||||
e.Skip()
|
||||
|
||||
if e.ButtonDown():
|
||||
self.CaptureMouse()
|
||||
self.oldpos = (e.GetX(), e.GetY())
|
||||
|
||||
if e.Entering():
|
||||
self.oldpos = (e.GetX(), e.GetY())
|
||||
|
||||
if e.ButtonUp():
|
||||
self.ReleaseMouse()
|
||||
if self.IsFloating():
|
||||
homepos = self.parentframe.ClientToScreen(wxPoint(0,0))
|
||||
floatpos = self.floatframe.GetPosition()
|
||||
if (abs(homepos.x - floatpos.x) < _DOCKTHRESHOLD and
|
||||
abs(homepos.y - floatpos.y) < _DOCKTHRESHOLD):
|
||||
self.Float(0)
|
||||
return
|
||||
|
||||
if e.Dragging():
|
||||
if not self.IsFloating():
|
||||
self.Float(true)
|
||||
self.oldpos = (e.GetX(), e.GetY())
|
||||
else:
|
||||
if hasattr(self, 'oldpos'):
|
||||
loc = self.floatframe.GetPosition()
|
||||
pt = wxPoint(loc.x - (self.oldpos[0]-e.GetX()), loc.y - (self.oldpos[1]-e.GetY()))
|
||||
self.floatframe.Move(pt)
|
||||
|
||||
|
||||
|
||||
def _SetFauxBarVisible(self, vis):
|
||||
return
|
||||
if vis:
|
||||
if self.parentframe.GetToolBar() == None:
|
||||
if not hasattr(self, 'nullbar'):
|
||||
self.nullbar = wxToolBar(self.parentframe, -1)
|
||||
print "Adding fauxbar."
|
||||
self.nullbar.Reparent(self.parentframe)
|
||||
print "Reparented."
|
||||
self.parentframe.SetToolBar(self.nullbar)
|
||||
print "Set toolbar"
|
||||
col = wxNamedColour("GREY")
|
||||
self.nullbar.SetBackgroundColour(col)
|
||||
print "Set color"
|
||||
size = self.parentframe.GetSize()
|
||||
self.parentframe.SetSize(wxSize(0,0))
|
||||
self.parentframe.SetSize(size)
|
||||
print "Set size"
|
||||
else:
|
||||
print self.parentframe.GetToolBar()
|
||||
else:
|
||||
if self.parentframe.GetToolBar() != None:
|
||||
print "Removing fauxbar"
|
||||
self.nullbar.Reparent(self.floatframe)
|
||||
self.parentframe.SetToolBar(None)
|
||||
size = self.parentframe.GetSize()
|
||||
self.parentframe.SetSize(wxSize(0,0))
|
||||
self.parentframe.SetSize(size)
|
||||
|
||||
|
||||
|
263
wxPython/wxPython/lib/grids.py
Normal file
263
wxPython/wxPython/lib/grids.py
Normal file
@@ -0,0 +1,263 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.grids
|
||||
# Purpose: An example sizer derived from the C++ wxPySizer that
|
||||
# sizes items in a fixed or flexible grid.
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 21-Sept-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1999 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
In this module you will find wxGridSizer and wxFlexGridSizer.
|
||||
|
||||
wxGridSizer: Sizes and positions items such that all rows are the same
|
||||
height and all columns are the same width. You can specify a gap in
|
||||
pixels to be used between the rows and/or the columns. When you
|
||||
create the sizer you specify the number of rows or the number of
|
||||
columns and then as you add items it figures out the other dimension
|
||||
automatically. Like other sizers, items can be set to fill their
|
||||
available space, or to be aligned on a side, in a corner, or in the
|
||||
center of the space. When the sizer is resized, all the items are
|
||||
resized the same amount so all rows and all columns remain the same
|
||||
size.
|
||||
|
||||
wxFlexGridSizer: Derives from wxGridSizer and adds the ability for
|
||||
particular rows and/or columns to be marked as growable. This means
|
||||
that when the sizer changes size, the growable rows and colums are the
|
||||
ones that stretch. The others remain at their initial size.
|
||||
|
||||
See the demo for a couple examples for how to use them.
|
||||
"""
|
||||
|
||||
|
||||
from wxPython.wx import *
|
||||
|
||||
import operator
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class wxGridSizer(wxPySizer):
|
||||
def __init__(self, rows=0, cols=0, hgap=0, vgap=0):
|
||||
wxPySizer.__init__(self)
|
||||
if rows == 0 and cols == 0:
|
||||
raise ValueError, "rows and cols cannot both be zero"
|
||||
|
||||
self.rows = rows
|
||||
self.cols = cols
|
||||
self.hgap = hgap
|
||||
self.vgap = vgap
|
||||
|
||||
|
||||
def SetRows(self, rows):
|
||||
if rows == 0 and self.cols == 0:
|
||||
raise ValueError, "rows and cols cannot both be zero"
|
||||
self.rows = rows
|
||||
|
||||
def SetColumns(self, cols):
|
||||
if self.rows == 0 and cols == 0:
|
||||
raise ValueError, "rows and cols cannot both be zero"
|
||||
self.cols = cols
|
||||
|
||||
def GetRows(self):
|
||||
return self.rows
|
||||
|
||||
def GetColumns(self):
|
||||
return self.cols
|
||||
|
||||
def SetHgap(self, hgap):
|
||||
self.hgap = hgap
|
||||
|
||||
def SetVgap(self, vgap):
|
||||
self.vgap = vgap
|
||||
|
||||
def GetHgap(self, hgap):
|
||||
return self.hgap
|
||||
|
||||
def GetVgap(self, vgap):
|
||||
return self.vgap
|
||||
|
||||
#--------------------------------------------------
|
||||
def CalcMin(self):
|
||||
items = self.GetChildren()
|
||||
nitems = len(items)
|
||||
nrows = self.rows
|
||||
ncols = self.cols
|
||||
|
||||
if ncols > 0:
|
||||
nrows = (nitems + ncols-1) / ncols
|
||||
else:
|
||||
ncols = (nitems + nrows-1) / nrows
|
||||
|
||||
# Find the max width and height for any component.
|
||||
w = 0
|
||||
h = 0
|
||||
for item in items:
|
||||
size = item.CalcMin()
|
||||
w = max(w, size.width)
|
||||
h = max(h, size.height)
|
||||
|
||||
return wxSize(ncols * w + (ncols-1) * self.hgap,
|
||||
nrows * h + (nrows-1) * self.vgap)
|
||||
|
||||
|
||||
#--------------------------------------------------
|
||||
def RecalcSizes(self):
|
||||
items = self.GetChildren()
|
||||
if not items:
|
||||
return
|
||||
|
||||
nitems = len(items)
|
||||
nrows = self.rows
|
||||
ncols = self.cols
|
||||
|
||||
if ncols > 0:
|
||||
nrows = (nitems + ncols-1) / ncols
|
||||
else:
|
||||
ncols = (nitems + nrows-1) / nrows
|
||||
|
||||
|
||||
sz = self.GetSize()
|
||||
pt = self.GetPosition()
|
||||
w = (sz.width - (ncols - 1) * self.hgap) / ncols;
|
||||
h = (sz.height - (nrows - 1) * self.vgap) / nrows;
|
||||
|
||||
x = pt.x
|
||||
for c in range(ncols):
|
||||
y = pt.y
|
||||
for r in range(nrows):
|
||||
i = r * ncols + c
|
||||
if i < nitems:
|
||||
self.SetItemBounds(items[i], x, y, w, h)
|
||||
y = y + h + self.vgap
|
||||
x = x + w + self.hgap
|
||||
|
||||
|
||||
#--------------------------------------------------
|
||||
def SetItemBounds(self, item, x, y, w, h):
|
||||
# calculate the item's size and position within
|
||||
# its grid cell
|
||||
ipt = wxPoint(x, y)
|
||||
isz = item.CalcMin()
|
||||
flag = item.GetFlag()
|
||||
|
||||
if flag & wxEXPAND or flag & wxSHAPED:
|
||||
isz = wxSize(w, h)
|
||||
else:
|
||||
if flag & wxALIGN_CENTER_HORIZONTAL:
|
||||
ipt.x = x + (w - isz.width) / 2
|
||||
elif flag & wxALIGN_RIGHT:
|
||||
ipt.x = x + (w - isz.width)
|
||||
|
||||
if flag & wxALIGN_CENTER_VERTICAL:
|
||||
ipt.y = y + (h - isz.height) / 2
|
||||
elif flag & wxALIGN_BOTTOM:
|
||||
ipt.y = y + (h - isz.height)
|
||||
|
||||
item.SetDimension(ipt, isz)
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
class wxFlexGridSizer(wxGridSizer):
|
||||
def __init__(self, rows=0, cols=0, hgap=0, vgap=0):
|
||||
wxGridSizer.__init__(self, rows, cols, hgap, vgap)
|
||||
self.rowHeights = []
|
||||
self.colWidths = []
|
||||
self.growableRows = []
|
||||
self.growableCols = []
|
||||
|
||||
def AddGrowableRow(self, idx):
|
||||
self.growableRows.append(idx)
|
||||
|
||||
def AddGrowableCol(self, idx):
|
||||
self.growableCols.append(idx)
|
||||
|
||||
#--------------------------------------------------
|
||||
def CalcMin(self):
|
||||
items = self.GetChildren()
|
||||
nitems = len(items)
|
||||
nrows = self.rows
|
||||
ncols = self.cols
|
||||
|
||||
if ncols > 0:
|
||||
nrows = (nitems + ncols-1) / ncols
|
||||
else:
|
||||
ncols = (nitems + nrows-1) / nrows
|
||||
|
||||
# Find the max width and height for any component.
|
||||
self.rowHeights = [0] * nrows
|
||||
self.colWidths = [0] * ncols
|
||||
for i in range(len(items)):
|
||||
size = items[i].CalcMin()
|
||||
row = i / ncols
|
||||
col = i % ncols
|
||||
self.rowHeights[row] = max(size.height, self.rowHeights[row])
|
||||
self.colWidths[col] = max(size.width, self.colWidths[col])
|
||||
|
||||
# Add up all the widths and heights
|
||||
cellsWidth = reduce(operator.__add__, self.colWidths)
|
||||
cellHeight = reduce(operator.__add__, self.rowHeights)
|
||||
|
||||
return wxSize(cellsWidth + (ncols-1) * self.hgap,
|
||||
cellHeight + (nrows-1) * self.vgap)
|
||||
|
||||
|
||||
#--------------------------------------------------
|
||||
def RecalcSizes(self):
|
||||
items = self.GetChildren()
|
||||
if not items:
|
||||
return
|
||||
|
||||
nitems = len(items)
|
||||
nrows = self.rows
|
||||
ncols = self.cols
|
||||
|
||||
if ncols > 0:
|
||||
nrows = (nitems + ncols-1) / ncols
|
||||
else:
|
||||
ncols = (nitems + nrows-1) / nrows
|
||||
|
||||
minsz = self.CalcMin()
|
||||
sz = self.GetSize()
|
||||
pt = self.GetPosition()
|
||||
|
||||
# Check for growables
|
||||
if self.growableRows and sz.height > minsz.height:
|
||||
delta = (sz.height - minsz.height) / len(self.growableRows)
|
||||
for idx in self.growableRows:
|
||||
self.rowHeights[idx] = self.rowHeights[idx] + delta
|
||||
|
||||
if self.growableCols and sz.width > minsz.width:
|
||||
delta = (sz.width - minsz.width) / len(self.growableCols)
|
||||
for idx in self.growableCols:
|
||||
self.colWidths[idx] = self.colWidths[idx] + delta
|
||||
|
||||
# bottom right corner
|
||||
sz = wxSize(pt.x + sz.width, pt.y + sz.height)
|
||||
|
||||
# Layout each cell
|
||||
x = pt.x
|
||||
for c in range(ncols):
|
||||
y = pt.y
|
||||
for r in range(nrows):
|
||||
i = r * ncols + c
|
||||
if i < nitems:
|
||||
w = max(0, min(self.colWidths[c], sz.width - x))
|
||||
h = max(0, min(self.rowHeights[r], sz.height - y))
|
||||
self.SetItemBounds(items[i], x, y, w, h)
|
||||
y = y + self.rowHeights[r] + self.vgap
|
||||
x = x + self.colWidths[c] + self.hgap
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
263
wxPython/wxPython/lib/layoutf.py
Normal file
263
wxPython/wxPython/lib/layoutf.py
Normal file
@@ -0,0 +1,263 @@
|
||||
from wxPython.wx import wxLayoutConstraints,\
|
||||
wxTop, wxLeft, wxBottom, wxRight, \
|
||||
wxHeight, wxWidth, wxCentreX, wxCentreY
|
||||
import re,string
|
||||
|
||||
class Layoutf(wxLayoutConstraints):
|
||||
"""
|
||||
The class Layoutf(wxLayoutConstraints) presents a simplification
|
||||
of the wxLayoutConstraints syntax. The name Layoutf is choosen
|
||||
because of the similarity with C's printf function.
|
||||
|
||||
Quick Example:
|
||||
|
||||
lc = Layoutf('t=t#1;l=r10#2;r!100;h%h50#1', (self, self.panel))
|
||||
|
||||
is equivalent to
|
||||
|
||||
lc = wxLayoutContraints()
|
||||
lc.top.SameAs(self, wxTop)
|
||||
lc.left.SameAs(self.panel, wxRight, 10)
|
||||
lc.right.Absolute(100)
|
||||
lc.height.PercentOf(self, wxHeight, 50)
|
||||
|
||||
Usage:
|
||||
|
||||
You can give a constraint string to the Layoutf constructor,
|
||||
or use the 'pack' method. The following are equivalent:
|
||||
|
||||
lc = Layoutf('t=t#1;l=r#2;r!100;h%h50#1', (self, self.panel))
|
||||
|
||||
and
|
||||
|
||||
lc = Layoutf()
|
||||
lc.pack('t=t#1;l=r#2;r!100;h%h50#1', (self, self.panel))
|
||||
|
||||
Besides 'pack' there's also 'debug_pack' which does not set
|
||||
constraints, but prints traditional wxLayoutConstraint calls to
|
||||
stdout.
|
||||
|
||||
The calls to the Layoutf constructor and pack methods have
|
||||
the following argument list:
|
||||
|
||||
(constraint_string, objects_tuple)
|
||||
|
||||
Constraint String syntax:
|
||||
|
||||
Constraint directives are separated by semi-colons. You
|
||||
generally (always?) need four directives to completely describe a
|
||||
subwindow's location.
|
||||
|
||||
A single directive has either of the following forms:
|
||||
|
||||
1. <own attribute><compare operation>[numerical argument]
|
||||
for example r!100 -> lc.right.Absolute(100) )
|
||||
and w* -> lc.width.AsIs()
|
||||
|
||||
2. <own attribute><compare operation>[numerical argument]
|
||||
#<compare object nr.>
|
||||
for example t_10#2 (lc.top.Below(<second obj>, 10)
|
||||
|
||||
3. <own attribute><compare operation><compare attribute>
|
||||
[numerical argument]#<compare object nr.>
|
||||
for example w%h50#2 ( lc.width.PercentOf(<second obj>,
|
||||
wxHeight, 50) and t=b#1 ( lc.top.SameAs(<first obj>,
|
||||
wxBottom) )
|
||||
|
||||
Which one you need is defined by the <compare operation>
|
||||
type. The following take type 1 (no object to compare with):
|
||||
|
||||
'!': 'Absolute', '?': 'Unconstrained', '*': 'AsIs'
|
||||
|
||||
These take type 2 (need to be compared with another object)
|
||||
|
||||
'<': 'LeftOf', '>': 'RightOf', '^': 'Above', '_': 'Below'
|
||||
|
||||
These take type 3 (need to be compared to another object
|
||||
attribute)
|
||||
|
||||
'=': 'SameAs', '%': 'PercentOf'
|
||||
|
||||
For all types, the <own attribute> letter can be any of
|
||||
|
||||
't': 'top', 'l': 'left', 'b': 'bottom',
|
||||
'r': 'right', 'h': 'height', 'w': 'width',
|
||||
'x': 'centreX', 'y': 'centreY'
|
||||
|
||||
If the operation takes an (optional) numerical argument, place it
|
||||
in [numerical argument]. For type 3 directives, the <compare
|
||||
attribute> letter can be any of
|
||||
|
||||
't': 'wxTop', 'l': 'wxLeft', 'b': 'wxBottom'
|
||||
'r': 'wxRight', 'h': 'wxHeight', 'w': 'wxWidth',
|
||||
'x': 'wxCentreX', 'y': 'wxCentreY'
|
||||
|
||||
Note that these are the same letters as used for <own attribute>,
|
||||
so you'll only need to remember one set. Finally, the object
|
||||
whose attribute is refered to, is specified by #<compare object
|
||||
nr>, where <compare object nr> is the 1-based (stupid, I know,
|
||||
but I've gotten used to it) index of the object in the
|
||||
objects_tuple argument.
|
||||
|
||||
Bugs:
|
||||
|
||||
Not entirely happy about the logic in the order of arguments
|
||||
after the <compare operation> character.
|
||||
|
||||
Not all wxLayoutConstraint methods are included in the
|
||||
syntax. However, the type 3 directives are generally the most
|
||||
used. Further excuse: wxWindows layout constraints are at the
|
||||
time of this writing not documented.
|
||||
|
||||
"""
|
||||
|
||||
attr_d = { 't': 'top', 'l': 'left', 'b': 'bottom',
|
||||
'r': 'right', 'h': 'height', 'w': 'width',
|
||||
'x': 'centreX', 'y': 'centreY' }
|
||||
op_d = { '=': 'SameAs', '%': 'PercentOf', '<': 'LeftOf',
|
||||
'>': 'RightOf', '^': 'Above', '_': 'Below',
|
||||
'!': 'Absolute', '?': 'Unconstrained', '*': 'AsIs' }
|
||||
cmp_d = { 't': 'wxTop', 'l': 'wxLeft', 'b': 'wxBottom',
|
||||
'r': 'wxRight', 'h': 'wxHeight', 'w': 'wxWidth',
|
||||
'x': 'wxCentreX', 'y': 'wxCentreY' }
|
||||
|
||||
rexp1 = re.compile('^\s*([tlrbhwxy])\s*([!\?\*])\s*(\d*)\s*$')
|
||||
rexp2 = re.compile('^\s*([tlrbhwxy])\s*([=%<>^_])\s*([tlrbhwxy]?)\s*(\d*)\s*#(\d+)\s*$')
|
||||
|
||||
def __init__(self,pstr=None,winlist=None):
|
||||
wxLayoutConstraints.__init__(self)
|
||||
if pstr:
|
||||
self.pack(pstr,winlist)
|
||||
|
||||
def pack(self, pstr, winlist):
|
||||
pstr = string.lower(pstr)
|
||||
for item in string.split(pstr,';'):
|
||||
m = self.rexp1.match(item)
|
||||
if m:
|
||||
g = list(m.groups())
|
||||
attr = getattr(self, self.attr_d[g[0]])
|
||||
func = getattr(attr, self.op_d[g[1]])
|
||||
if g[1] == '!':
|
||||
func(int(g[2]))
|
||||
else:
|
||||
func()
|
||||
continue
|
||||
m = self.rexp2.match(item)
|
||||
if not m: raise ValueError
|
||||
g = list(m.groups())
|
||||
attr = getattr(self, self.attr_d[g[0]])
|
||||
func = getattr(attr, self.op_d[g[1]])
|
||||
if g[3]: g[3] = int(g[3])
|
||||
else: g[3] = None;
|
||||
g[4] = int(g[4]) - 1
|
||||
if g[1] in '<>^_':
|
||||
if g[3]: func(winlist[g[4]], g[3])
|
||||
else: func(winlist[g[4]])
|
||||
else:
|
||||
cmp = eval(self.cmp_d[g[2]])
|
||||
if g[3]: func(winlist[g[4]], cmp, g[3])
|
||||
else: func(winlist[g[4]], cmp)
|
||||
|
||||
def debug_pack(self, pstr, winlist):
|
||||
pstr = string.lower(pstr)
|
||||
for item in string.split(pstr,';'):
|
||||
m = self.rexp1.match(item)
|
||||
if m:
|
||||
g = list(m.groups())
|
||||
attr = getattr(self, self.attr_d[g[0]])
|
||||
func = getattr(attr, self.op_d[g[1]])
|
||||
if g[1] == '!':
|
||||
print "%s.%s.%s(%s)" % \
|
||||
('self',self.attr_d[g[0]],self.op_d[g[1]],g[2])
|
||||
else:
|
||||
print "%s.%s.%s()" % \
|
||||
('self',self.attr_d[g[0]],self.op_d[g[1]])
|
||||
continue
|
||||
m = self.rexp2.match(item)
|
||||
if not m: raise ValueError
|
||||
g = list(m.groups())
|
||||
if g[3]: g[3] = int(g[3])
|
||||
else: g[3] = 0;
|
||||
g[4] = int(g[4]) - 1
|
||||
if g[1] in '<>^_':
|
||||
if g[3]: print "%s.%s.%s(%s,%d)" % \
|
||||
('self',self.attr_d[g[0]],self.op_d[g[1]],winlist[g[4]],
|
||||
g[3])
|
||||
else: print "%s.%s.%s(%s)" % \
|
||||
('self',self.attr_d[g[0]],self.op_d[g[1]],winlist[g[4]])
|
||||
else:
|
||||
if g[3]: print "%s.%s.%s(%s,%s,%d)" % \
|
||||
('self',self.attr_d[g[0]],self.op_d[g[1]],winlist[g[4]],
|
||||
self.cmp_d[g[2]],g[3])
|
||||
else: print "%s.%s.%s(%s,%s)" % \
|
||||
('self',self.attr_d[g[0]],self.op_d[g[1]],winlist[g[4]],
|
||||
self.cmp_d[g[2]])
|
||||
|
||||
if __name__=='__main__':
|
||||
from wxPython.wx import *
|
||||
|
||||
class TestLayoutf(wxFrame):
|
||||
def __init__(self, parent):
|
||||
wxFrame.__init__(self, parent, -1, 'Test Layout Constraints',
|
||||
wxPyDefaultPosition, wxSize(500, 300))
|
||||
EVT_CLOSE(self, self.OnCloseWindow)
|
||||
|
||||
self.SetAutoLayout(true)
|
||||
EVT_BUTTON(self, 100, self.OnButton)
|
||||
EVT_BUTTON(self, 101, self.OnAbout)
|
||||
|
||||
self.panelA = wxWindow(self, -1, wxPyDefaultPosition, wxPyDefaultSize, wxSIMPLE_BORDER)
|
||||
self.panelA.SetBackgroundColour(wxBLUE)
|
||||
self.panelA.SetConstraints(Layoutf('t=t10#1;l=l10#1;b=b10#1;r%r50#1',(self,)))
|
||||
|
||||
self.panelB = wxWindow(self, -1, wxPyDefaultPosition, wxPyDefaultSize, wxSIMPLE_BORDER)
|
||||
self.panelB.SetBackgroundColour(wxRED)
|
||||
self.panelB.SetConstraints(Layoutf('t=t10#1;r=r10#1;b%b30#1;l>10#2', (self,self.panelA)))
|
||||
|
||||
self.panelC = wxWindow(self, -1, wxPyDefaultPosition, wxPyDefaultSize, wxSIMPLE_BORDER)
|
||||
self.panelC.SetBackgroundColour(wxWHITE)
|
||||
self.panelC.SetConstraints(Layoutf('t_10#3;r=r10#1;b=b10#1;l>10#2', (self,self.panelA,self.panelB)))
|
||||
|
||||
b = wxButton(self.panelA, 101, ' About: ')
|
||||
b.SetConstraints(Layoutf('X=X#1;Y=Y#1;h*;w%w50#1', (self.panelA,)))
|
||||
|
||||
b = wxButton(self.panelB, 100, ' Panel B ')
|
||||
b.SetConstraints(Layoutf('t=t2#1;r=r4#1;h*;w*', (self.panelB,)))
|
||||
|
||||
self.panelD = wxWindow(self.panelC, -1, wxPyDefaultPosition, wxPyDefaultSize, wxSIMPLE_BORDER)
|
||||
self.panelD.SetBackgroundColour(wxGREEN)
|
||||
self.panelD.SetConstraints(Layoutf('b%h50#1;r%w50#1;h=h#2;w=w#2', (self.panelC, b)))
|
||||
|
||||
b = wxButton(self.panelC, 100, ' Panel C ')
|
||||
b.SetConstraints(Layoutf('t_#1;l>#1;h*;w*', (self.panelD,)))
|
||||
|
||||
wxStaticText(self.panelD, -1, "Panel D", wxPoint(4, 4)).SetBackgroundColour(wxGREEN)
|
||||
|
||||
def OnButton(self, event):
|
||||
self.Close(true)
|
||||
|
||||
def OnAbout(self, event):
|
||||
try:
|
||||
from dialogs import wxScrolledMessageDialog
|
||||
msg = wxScrolledMessageDialog(self, Layoutf.__doc__, "about")
|
||||
msg.ShowModal()
|
||||
except:
|
||||
print msg
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
class TestApp(wxApp):
|
||||
def OnInit(self):
|
||||
frame = TestLayoutf(NULL)
|
||||
frame.Show(1)
|
||||
self.SetTopWindow(frame)
|
||||
return 1
|
||||
|
||||
app = TestApp(0)
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
1135
wxPython/wxPython/lib/mvctree.py
Normal file
1135
wxPython/wxPython/lib/mvctree.py
Normal file
File diff suppressed because it is too large
Load Diff
324
wxPython/wxPython/lib/pyshell.py
Normal file
324
wxPython/wxPython/lib/pyshell.py
Normal file
@@ -0,0 +1,324 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.pyshell
|
||||
# Purpose: A Python Interactive Interpreter running in a wxStyledTextCtrl
|
||||
# window.
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 7-July-2000
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 2000 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
PyShellWindow is a class that provides an Interactive Interpreter running
|
||||
inside a wxStyledTextCtrl, similar to the Python shell windows found in
|
||||
IDLE and PythonWin.
|
||||
|
||||
There is still much to be done to improve this class, such as line
|
||||
buffering/recall, autoindent, calltips, autocomplete, etc... But
|
||||
it's a good start.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from wxPython.wx import *
|
||||
from wxPython.stc import *
|
||||
|
||||
import sys, string, keyword
|
||||
from code import InteractiveInterpreter
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# default styles, etc. to use for the STC
|
||||
|
||||
if wxPlatform == '__WXMSW__':
|
||||
_defaultSize = 8
|
||||
else:
|
||||
_defaultSize = 10
|
||||
|
||||
|
||||
_default_properties = {
|
||||
'selMargin' : 0,
|
||||
'marginWidth' : 1,
|
||||
'ps1' : '>>> ',
|
||||
'stdout' : 'fore:#0000FF',
|
||||
'stderr' : 'fore:#007f00',
|
||||
'trace' : 'fore:#FF0000',
|
||||
|
||||
'default' : 'size:%d' % _defaultSize,
|
||||
'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
|
||||
'bracebad' : 'fore:#000000,back:#FF0000,bold',
|
||||
|
||||
# properties for the various Python lexer styles
|
||||
'comment' : 'fore:#007F00',
|
||||
'number' : 'fore:#007F7F',
|
||||
'string' : 'fore:#7F007F,italic',
|
||||
'char' : 'fore:#7F007F,italic',
|
||||
'keyword' : 'fore:#00007F,bold',
|
||||
'triple' : 'fore:#7F0000',
|
||||
'tripledouble': 'fore:#7F0000',
|
||||
'class' : 'fore:#0000FF,bold,underline',
|
||||
'def' : 'fore:#007F7F,bold',
|
||||
'operator' : 'bold',
|
||||
|
||||
}
|
||||
|
||||
|
||||
# new style numbers
|
||||
_stdout_style = 15
|
||||
_stderr_style = 16
|
||||
_trace_style = 17
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class PyShellWindow(wxStyledTextCtrl, InteractiveInterpreter):
|
||||
def __init__(self, parent, ID, pos=wxDefaultPosition,
|
||||
size=wxDefaultSize, style=0,
|
||||
locals=None, properties=None, banner=None):
|
||||
wxStyledTextCtrl.__init__(self, parent, ID, pos, size, style)
|
||||
InteractiveInterpreter.__init__(self, locals)
|
||||
|
||||
self.lastPromptPos = 0
|
||||
|
||||
# the line cache is used to cycle through previous commands
|
||||
self.lines = []
|
||||
self.lastUsedLine = self.curLine = 0
|
||||
|
||||
# set defaults and then deal with any user defined properties
|
||||
self.props = {}
|
||||
self.props.update(_default_properties)
|
||||
if properties:
|
||||
self.props.update(properties)
|
||||
self.UpdateProperties()
|
||||
|
||||
# copyright/banner message
|
||||
if banner is None:
|
||||
self.write("Python %s on %s\n%s\n(%s)\n" %
|
||||
(sys.version, sys.platform, sys.copyright,
|
||||
self.__class__.__name__))
|
||||
else:
|
||||
self.write("%s\n" % banner)
|
||||
|
||||
# write the initial prompt
|
||||
self.Prompt()
|
||||
|
||||
# Event handlers
|
||||
EVT_KEY_DOWN(self, self.OnKey)
|
||||
EVT_STC_UPDATEUI(self, ID, self.OnUpdateUI)
|
||||
EVT_STC_STYLENEEDED(self, ID, self.OnStyle)
|
||||
|
||||
|
||||
def GetLocals(self): return self.locals
|
||||
def SetLocals(self, locals): self.locals = locals
|
||||
|
||||
def GetProperties(self): return self.props
|
||||
def SetProperties(self, properties):
|
||||
self.props.update(properties)
|
||||
self.UpdateProperties()
|
||||
|
||||
|
||||
def UpdateProperties(self):
|
||||
"""
|
||||
Reset the editor and other settings based on the contents of the
|
||||
current properties dictionary.
|
||||
"""
|
||||
p = self.props
|
||||
|
||||
self.SetEdgeMode(wxSTC_EDGE_LINE)
|
||||
self.SetEdgeColumn(80)
|
||||
|
||||
|
||||
# set the selection margin and window margin
|
||||
self.SetMarginWidth(1, p['selMargin'])
|
||||
self.SetMargins(p['marginWidth'], p['marginWidth'])
|
||||
|
||||
# styles
|
||||
self.StyleSetSpec(wxSTC_STYLE_DEFAULT, p['default'])
|
||||
self.StyleClearAll()
|
||||
self.StyleSetSpec(_stdout_style, p['stdout'])
|
||||
self.StyleSetSpec(_stderr_style, p['stderr'])
|
||||
self.StyleSetSpec(_trace_style, p['trace'])
|
||||
|
||||
self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, p['bracegood'])
|
||||
self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, p['bracebad'])
|
||||
self.StyleSetSpec(SCE_P_COMMENTLINE, p['comment'])
|
||||
self.StyleSetSpec(SCE_P_NUMBER, p['number'])
|
||||
self.StyleSetSpec(SCE_P_STRING, p['string'])
|
||||
self.StyleSetSpec(SCE_P_CHARACTER, p['char'])
|
||||
self.StyleSetSpec(SCE_P_WORD, p['keyword'])
|
||||
self.StyleSetSpec(SCE_P_TRIPLE, p['triple'])
|
||||
self.StyleSetSpec(SCE_P_TRIPLEDOUBLE, p['tripledouble'])
|
||||
self.StyleSetSpec(SCE_P_CLASSNAME, p['class'])
|
||||
self.StyleSetSpec(SCE_P_DEFNAME, p['def'])
|
||||
self.StyleSetSpec(SCE_P_OPERATOR, p['operator'])
|
||||
self.StyleSetSpec(SCE_P_COMMENTBLOCK, p['comment'])
|
||||
|
||||
|
||||
# used for writing to stdout, etc.
|
||||
def _write(self, text, style=_stdout_style):
|
||||
self.lastPromptPos = 0
|
||||
pos = self.GetCurrentPos()
|
||||
self.AddText(text)
|
||||
self.StartStyling(pos, 0xFF)
|
||||
self.SetStyleFor(len(text), style)
|
||||
self.EnsureCaretVisible()
|
||||
wxYield()
|
||||
|
||||
write = _write
|
||||
|
||||
def writeTrace(self, text):
|
||||
self._write(text, _trace_style)
|
||||
|
||||
|
||||
def Prompt(self):
|
||||
# is the current line non-empty?
|
||||
text, pos = self.GetCurrentLineText()
|
||||
if pos != 0:
|
||||
self.AddText('\n')
|
||||
self.AddText(self.props['ps1'])
|
||||
self.lastPromptPos = self.GetCurrentPos()
|
||||
self.EnsureCaretVisible()
|
||||
self.ScrollToColumn(0)
|
||||
|
||||
|
||||
def PushLine(self, text):
|
||||
# TODO: Add the text to the line cache, manage the cache so
|
||||
# it doesn't get too big.
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def OnKey(self, evt):
|
||||
key = evt.KeyCode()
|
||||
if key == WXK_RETURN:
|
||||
pos = self.GetCurrentPos()
|
||||
lastPos = self.GetTextLength()
|
||||
|
||||
# if not on the last line, duplicate the current line
|
||||
if self.GetLineCount()-1 != self.GetCurrentLine():
|
||||
text, col = self.GetCurrentLineText()
|
||||
prompt = self.props['ps1']
|
||||
lp = len(prompt)
|
||||
if text[:lp] == prompt:
|
||||
text = text[lp:]
|
||||
|
||||
self.SetSelection(self.lastPromptPos, lastPos)
|
||||
self.ReplaceSelection(text[:-1])
|
||||
|
||||
else: # try to execute the text from the prompt to the end
|
||||
if lastPos == self.lastPromptPos:
|
||||
self.AddText('\n')
|
||||
self.Prompt()
|
||||
return
|
||||
|
||||
text = self.GetTextRange(self.lastPromptPos, lastPos)
|
||||
self.AddText('\n')
|
||||
|
||||
more = self.runsource(text)
|
||||
if not more:
|
||||
self.PushLine(text)
|
||||
self.Prompt()
|
||||
|
||||
# TODO: Add handlers for Alt-P and Alt-N to cycle through entries
|
||||
# in the line cache
|
||||
|
||||
else:
|
||||
evt.Skip()
|
||||
|
||||
|
||||
def OnStyle(self, evt):
|
||||
# Only style from the prompt pos to the end
|
||||
lastPos = self.GetTextLength()
|
||||
if self.lastPromptPos and self.lastPromptPos != lastPos:
|
||||
self.SetLexer(wxSTC_LEX_PYTHON)
|
||||
self.SetKeywords(0, string.join(keyword.kwlist))
|
||||
|
||||
self.Colourise(self.lastPromptPos, lastPos)
|
||||
|
||||
self.SetLexer(0)
|
||||
|
||||
|
||||
def OnUpdateUI(self, evt):
|
||||
# check for matching braces
|
||||
braceAtCaret = -1
|
||||
braceOpposite = -1
|
||||
charBefore = None
|
||||
caretPos = self.GetCurrentPos()
|
||||
if caretPos > 0:
|
||||
charBefore = self.GetCharAt(caretPos - 1)
|
||||
styleBefore = self.GetStyleAt(caretPos - 1)
|
||||
|
||||
# check before
|
||||
if charBefore and charBefore in "[]{}()" and ord(styleBefore) == SCE_P_OPERATOR:
|
||||
braceAtCaret = caretPos - 1
|
||||
|
||||
# check after
|
||||
if braceAtCaret < 0:
|
||||
charAfter = self.GetCharAt(caretPos)
|
||||
styleAfter = self.GetStyleAt(caretPos)
|
||||
if charAfter and charAfter in "[]{}()" and ord(styleAfter) == SCE_P_OPERATOR:
|
||||
braceAtCaret = caretPos
|
||||
|
||||
if braceAtCaret >= 0:
|
||||
braceOpposite = self.BraceMatch(braceAtCaret)
|
||||
|
||||
if braceAtCaret != -1 and braceOpposite == -1:
|
||||
self.BraceBadlight(braceAtCaret)
|
||||
else:
|
||||
self.BraceHighlight(braceAtCaret, braceOpposite)
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------
|
||||
# overloaded methods from InteractiveInterpreter
|
||||
def runsource(self, source):
|
||||
stdout, stderr = sys.stdout, sys.stderr
|
||||
sys.stdout = FauxFile(self, _stdout_style)
|
||||
sys.stderr = FauxFile(self, _stderr_style)
|
||||
|
||||
more = InteractiveInterpreter.runsource(self, source)
|
||||
|
||||
sys.stdout, sys.stderr = stdout, stderr
|
||||
return more
|
||||
|
||||
def showsyntaxerror(self, filename=None):
|
||||
self.write = self.writeTrace
|
||||
InteractiveInterpreter.showsyntaxerror(self, filename)
|
||||
self.write = self._write
|
||||
|
||||
def showtraceback(self):
|
||||
self.write = self.writeTrace
|
||||
InteractiveInterpreter.showtraceback(self)
|
||||
self.write = self._write
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class FauxFile:
|
||||
def __init__(self, psw, style):
|
||||
self.psw = psw
|
||||
self.style = style
|
||||
|
||||
def write(self, text):
|
||||
self.psw.write(text, self.style)
|
||||
|
||||
def writelines(self, lst):
|
||||
map(self.write, lst)
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# test code
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = wxPyWidgetTester(size = (640, 480))
|
||||
app.SetWidget(PyShellWindow, -1)
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
349
wxPython/wxPython/lib/shell.py
Normal file
349
wxPython/wxPython/lib/shell.py
Normal file
@@ -0,0 +1,349 @@
|
||||
# shell.py
|
||||
"""wxPython interactive shell
|
||||
|
||||
Copyright (c) 1999 SIA "ANK"
|
||||
|
||||
this module is free software. it may be used under same terms as Python itself
|
||||
|
||||
Notes:
|
||||
i would like to use command completion (see rlcompleter library module),
|
||||
but i cannot load it because i don't have readline...
|
||||
|
||||
History:
|
||||
03-oct-1999 [als] created
|
||||
04-oct-1999 [als] PyShellOutput.intro moved from __init__ parameters
|
||||
to class attributes; html debug disabled
|
||||
04-oct-1999 [als] fixed bug with class attributes
|
||||
input prompts and output styles added to customized demo
|
||||
some html cleanups
|
||||
04-oct-1999 [rpd] Changed to use the new sizers
|
||||
05-oct-1990 [als] changes inspired by code.InteractiveInterpreter()
|
||||
from Python Library. if i knew about this class earlier,
|
||||
i would rather inherit from it.
|
||||
renamed to wxPyShell.py since i've renounced the 8.3 scheme
|
||||
|
||||
"""
|
||||
__version__ ="$Revision$"
|
||||
# $RCSfile$
|
||||
|
||||
import sys, string, code, traceback
|
||||
from wxPython.wx import *
|
||||
from wxPython.html import *
|
||||
|
||||
|
||||
class PyShellInput(wxPanel):
|
||||
"""PyShell input window
|
||||
|
||||
"""
|
||||
PS1 =" Enter Command:"
|
||||
PS2 ="... continue:"
|
||||
def __init__(self, parent, shell, id=-1):
|
||||
"""Create input window
|
||||
|
||||
shell must be a PyShell object.
|
||||
it is used for exception handling, eval() namespaces,
|
||||
and shell.output is used for output
|
||||
(print's go to overridden stdout)
|
||||
"""
|
||||
wxPanel.__init__(self, parent, id)
|
||||
self.shell =shell
|
||||
# make a private copy of class attrs
|
||||
self.PS1 =PyShellInput.PS1
|
||||
self.PS2 =PyShellInput.PS2
|
||||
# create controls
|
||||
self.label =wxStaticText(self, -1, self.PS1)
|
||||
tid =wxNewId()
|
||||
self.entry =wxTextCtrl(self, tid, style = wxTE_MULTILINE)
|
||||
EVT_CHAR(self.entry, self.OnChar)
|
||||
self.entry.SetFont(wxFont(9, wxMODERN, wxNORMAL, wxNORMAL, false))
|
||||
sizer =wxBoxSizer(wxVERTICAL)
|
||||
sizer.AddMany([(self.label, 0, wxEXPAND), (self.entry, 1, wxEXPAND)])
|
||||
self.SetSizer(sizer)
|
||||
self.SetAutoLayout(true)
|
||||
EVT_SET_FOCUS(self, self.OnSetFocus)
|
||||
# when in "continuation" mode,
|
||||
# two consecutive newlines are required
|
||||
# to avoid execution of unfinished block
|
||||
self.first_line =1
|
||||
|
||||
def OnSetFocus(self, event):
|
||||
self.entry.SetFocus()
|
||||
|
||||
|
||||
def Clear(self, event=None):
|
||||
"""reset input state"""
|
||||
self.label.SetLabel(self.PS1)
|
||||
self.label.Refresh()
|
||||
self.entry.SetSelection(0, self.entry.GetLastPosition())
|
||||
self.first_line =1
|
||||
# self.entry.SetFocus()
|
||||
|
||||
def OnChar(self, event):
|
||||
"""called on CHARevent. executes input on newline"""
|
||||
# print "On Char:", event.__dict__.keys()
|
||||
if event.KeyCode() !=WXK_RETURN:
|
||||
# not of our business
|
||||
event.Skip()
|
||||
return
|
||||
text =self.entry.GetValue()
|
||||
# weird CRLF thingy
|
||||
text =string.replace(text, "\r\n", "\n")
|
||||
# see if we've finished
|
||||
if (not (self.first_line or text[-1] =="\n") # in continuation mode
|
||||
or (text[-1] =="\\") # escaped newline
|
||||
):
|
||||
# XXX should escaped newline put myself i "continuation" mode?
|
||||
event.Skip()
|
||||
return
|
||||
# ok, we can try to execute this
|
||||
rc =self.shell.TryExec(text)
|
||||
if rc:
|
||||
# code is incomplete; continue input
|
||||
if self.first_line:
|
||||
self.label.SetLabel(self.PS2)
|
||||
self.label.Refresh()
|
||||
self.first_line =0
|
||||
event.Skip()
|
||||
else:
|
||||
self.Clear()
|
||||
|
||||
class PyShellOutput(wxPanel):
|
||||
"""PyShell output window
|
||||
|
||||
for now, it is based on simple wxTextCtrl,
|
||||
but i'm looking at HTML classes to provide colorized output
|
||||
"""
|
||||
# attributes for for different (input, output, exception) display styles:
|
||||
# begin tag, end tag, newline
|
||||
in_style =(" <font color=\"#000080\"><tt>>>> ",
|
||||
"</tt></font><br>\n", "<br>\n... ")
|
||||
out_style =("<tt>", "</tt>\n", "<br>\n")
|
||||
exc_style =("<font color=\"#FF0000\"><tt>",
|
||||
"</tt></font>\n", "<br>\n")
|
||||
intro ="<H3>wxPython Interactive Shell</H3>\n"
|
||||
html_debug =0
|
||||
# entity references
|
||||
erefs =(("&", "&"), (">", ">"), ("<", "<"), (" ", " "))
|
||||
def __init__(self, parent, id=-1):
|
||||
wxPanel.__init__(self, parent, id)
|
||||
# make a private copy of class attrs
|
||||
self.in_style =PyShellOutput.in_style
|
||||
self.out_style =PyShellOutput.out_style
|
||||
self.exc_style =PyShellOutput.exc_style
|
||||
self.intro =PyShellOutput.intro
|
||||
self.html_debug =PyShellOutput.html_debug
|
||||
# create windows
|
||||
if self.html_debug:
|
||||
# this was used in html debugging,
|
||||
# but i don't want to delete it; it's funny
|
||||
splitter =wxSplitterWindow(self, -1)
|
||||
self.view =wxTextCtrl(splitter, -1,
|
||||
style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
|
||||
self.html =wxHtmlWindow(splitter)
|
||||
splitter.SplitVertically(self.view, self.html)
|
||||
splitter.SetSashPosition(40)
|
||||
splitter.SetMinimumPaneSize(3)
|
||||
self.client =splitter
|
||||
else:
|
||||
self.view =None
|
||||
self.html =wxHtmlWindow(self)
|
||||
self.client =self.html # used in OnSize()
|
||||
self.text =self.intro
|
||||
self.html.SetPage(self.text)
|
||||
self.html.SetAutoLayout(TRUE)
|
||||
self.line_buffer =""
|
||||
# refreshes are annoying
|
||||
self.in_batch =0
|
||||
self.dirty =0
|
||||
EVT_SIZE(self, self.OnSize)
|
||||
EVT_IDLE(self, self.OnIdle)
|
||||
|
||||
def OnSize(self, event):
|
||||
self.client.SetSize(self.GetClientSize())
|
||||
|
||||
def OnIdle(self, event):
|
||||
"""when there's nothing to do, we can update display"""
|
||||
if self.in_batch and self.dirty: self.UpdWindow()
|
||||
|
||||
def BeginBatch(self):
|
||||
"""do not refresh display till EndBatch()"""
|
||||
self.in_batch =1
|
||||
|
||||
def EndBatch(self):
|
||||
"""end batch; start updating display immediately"""
|
||||
self.in_batch =0
|
||||
if self.dirty: self.UpdWindow()
|
||||
|
||||
def UpdWindow(self):
|
||||
"""sync display with text buffer"""
|
||||
html =self.html
|
||||
html.SetPage(self.text)
|
||||
self.dirty =0
|
||||
# scroll to the end
|
||||
(x,y) =html.GetVirtualSize()
|
||||
html.Scroll(0, y)
|
||||
|
||||
def AddText(self, text, style=None):
|
||||
"""write text to output window"""
|
||||
# a trick needed to defer default from compile-time to execute-time
|
||||
if style ==None: style =self.out_style
|
||||
if 0 and __debug__: sys.__stdout__.write(text)
|
||||
# handle entities
|
||||
for (symbol, eref) in self.erefs:
|
||||
text =string.replace(text, symbol, eref)
|
||||
# replace newlines
|
||||
text =string.replace(text, "\n", style[2])
|
||||
# add to contents
|
||||
self.text =self.text +style[0] +text +style[1]
|
||||
if not self.in_batch: self.UpdWindow()
|
||||
else: self.dirty =1
|
||||
if self.html_debug:
|
||||
# html debug output needn't to be too large
|
||||
self.view.SetValue(self.text[-4096:])
|
||||
|
||||
def write(self, str, style=None):
|
||||
"""stdout-like interface"""
|
||||
if style ==None: style =self.out_style
|
||||
# do not process incomplete lines
|
||||
if len(str) <1:
|
||||
# hm... what was i supposed to do?
|
||||
return
|
||||
elif str[-1] !="\n":
|
||||
self.line_buffer =self.line_buffer +str
|
||||
else:
|
||||
self.AddText(self.line_buffer +str, style)
|
||||
self.line_buffer =""
|
||||
|
||||
def flush(self, style=None):
|
||||
"""write out all that was left in line buffer"""
|
||||
if style ==None: style =self.out_style
|
||||
self.AddText(self.line_buffer +"\n", style)
|
||||
|
||||
def write_in(self, str, style=None):
|
||||
"""write text in "input" style"""
|
||||
if style ==None: style =self.in_style
|
||||
self.AddText(str, style)
|
||||
|
||||
def write_exc(self, str, style=None):
|
||||
"""write text in "exception" style"""
|
||||
if style ==None: style =self.exc_style
|
||||
self.AddText(str, style)
|
||||
|
||||
class PyShell(wxPanel):
|
||||
"""interactive Python shell with wxPython interface
|
||||
|
||||
"""
|
||||
def __init__(self, parent, globals=globals(), locals={},
|
||||
id=-1, pos=wxDefaultPosition, size=wxDefaultSize,
|
||||
style=wxTAB_TRAVERSAL, name="shell"):
|
||||
"""create PyShell window"""
|
||||
wxPanel.__init__(self, parent, id, pos, size, style, name)
|
||||
self.globals =globals
|
||||
self.locals =locals
|
||||
splitter =wxSplitterWindow(self, -1)
|
||||
self.output =PyShellOutput(splitter)
|
||||
self.input =PyShellInput(splitter, self)
|
||||
self.input.SetFocus()
|
||||
splitter.SplitHorizontally(self.input, self.output)
|
||||
splitter.SetSashPosition(100)
|
||||
splitter.SetMinimumPaneSize(20)
|
||||
self.splitter =splitter
|
||||
EVT_SET_FOCUS(self, self.OnSetFocus)
|
||||
EVT_SIZE(self, self.OnSize)
|
||||
|
||||
def OnSetFocus(self, event):
|
||||
self.input.SetFocus()
|
||||
|
||||
def TryExec(self, source, symbol="single"):
|
||||
"""Compile and run some source in the interpreter.
|
||||
|
||||
borrowed from code.InteractiveInterpreter().runsource()
|
||||
as i said above, i would rather like to inherit from that class
|
||||
|
||||
returns 1 if more input is required, or 0, otherwise
|
||||
"""
|
||||
try:
|
||||
cc = code.compile_command(source, symbol=symbol)
|
||||
except (OverflowError, SyntaxError):
|
||||
# [als] hm... never seen anything of that kind
|
||||
self.ShowSyntaxError()
|
||||
return 0
|
||||
if cc is None:
|
||||
# source is incomplete
|
||||
return 1
|
||||
# source is sucessfully compiled
|
||||
out =self.output
|
||||
# redirect system stdout to the output window
|
||||
prev_out =sys.stdout
|
||||
sys.stdout =out
|
||||
# begin printout batch (html updates are deferred until EndBatch())
|
||||
out.BeginBatch()
|
||||
out.write_in(source)
|
||||
try:
|
||||
exec cc in self.globals, self.locals
|
||||
except SystemExit:
|
||||
# SystemExit is not handled and has to be re-raised
|
||||
raise
|
||||
except:
|
||||
# all other exceptions produce traceback output
|
||||
self.ShowException()
|
||||
# switch back to saved stdout
|
||||
sys.stdout =prev_out
|
||||
# commit printout
|
||||
out.flush()
|
||||
out.EndBatch()
|
||||
return 0
|
||||
|
||||
def ShowException(self):
|
||||
"""display the traceback for the latest exception"""
|
||||
(etype, value, tb) =sys.exc_info()
|
||||
# remove myself from traceback
|
||||
tblist =traceback.extract_tb(tb)[1:]
|
||||
msg =string.join(traceback.format_exception_only(etype, value)
|
||||
+traceback.format_list(tblist))
|
||||
self.output.write_exc(msg)
|
||||
|
||||
def ShowSyntaxError(self):
|
||||
"""display message about syntax error (no traceback here)"""
|
||||
(etype, value, tb) =sys.exc_info()
|
||||
msg =string.join(traceback.format_exception_only(etype, value))
|
||||
self.output.write_exc(msg)
|
||||
|
||||
def OnSize(self, event):
|
||||
self.splitter.SetSize(self.GetClientSize())
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
class MyFrame(wxFrame):
|
||||
"""Very standard Frame class. Nothing special here!"""
|
||||
def __init__(self, parent=NULL, id =-1,
|
||||
title="wxPython Interactive Shell"):
|
||||
wxFrame.__init__(self, parent, id, title)
|
||||
self.shell =PyShell(self)
|
||||
|
||||
class MyApp(wxApp):
|
||||
"""Demonstrates usage of both default and customized shells"""
|
||||
def OnInit(self):
|
||||
frame = MyFrame()
|
||||
frame.Show(TRUE)
|
||||
self.SetTopWindow(frame)
|
||||
## PyShellInput.PS1 =" let's get some work done..."
|
||||
## PyShellInput.PS2 =" ok, what do you really mean?"
|
||||
## PyShellOutput.in_style =(
|
||||
## "<I><font color=\"#008000\"><tt>>>> ",
|
||||
## "</tt></font></I><br>\n", "<br>\n... ")
|
||||
## PyShellOutput.out_style =(
|
||||
## "<font color=\"#000080\"><tt>",
|
||||
## "</tt></font><br>\n", "<br>\n")
|
||||
## PyShellOutput.exc_style =("<B><font color=\"#FF0000\"><tt>",
|
||||
## "</tt></font></B>\n", "<br>\n")
|
||||
## PyShellOutput.intro ="<I><B>Customized wxPython Shell</B>" \
|
||||
## "<br><-- move this sash to see html debug output</I><br>\n"
|
||||
## PyShellOutput.html_debug =1
|
||||
## frame = MyFrame(title="Customized wxPython Shell")
|
||||
## frame.Show(TRUE)
|
||||
return TRUE
|
||||
|
||||
app = MyApp(0)
|
||||
app.MainLoop()
|
||||
|
2
wxPython/wxPython/lib/sizers/.cvsignore
Normal file
2
wxPython/wxPython/lib/sizers/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
||||
*.pyc
|
||||
|
45
wxPython/wxPython/lib/sizers/__init__.py
Normal file
45
wxPython/wxPython/lib/sizers/__init__.py
Normal file
@@ -0,0 +1,45 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: __init__.py
|
||||
# Purpose: The presence of this file turns this directory into a
|
||||
# Python package.
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 18-May-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1998 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
from sizer import *
|
||||
from box import *
|
||||
from border import *
|
||||
from shape import *
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
_msg = """\
|
||||
Since the wxWindows library now includes its own sizers, the
|
||||
classes in wxPython.lib.sizers have been deprecated. Please
|
||||
see the Reference Manual for details of the new classes.
|
||||
|
||||
To contiunue using wxPython.lib.sizers without this
|
||||
message you can set the WXP_OLDSIZERS envronment
|
||||
variable to any value.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
from wxPython.wx import wxMessageDialog, wxOK, wxICON_EXCLAMATION, wxPlatform
|
||||
|
||||
if not os.environ.has_key('WXP_OLDSIZERS'):
|
||||
if wxPlatform == '__WXMSW__':
|
||||
dlg = wxMessageDialog(None, _msg,
|
||||
"Deprecated Feature",
|
||||
wxOK | wxICON_EXCLAMATION)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
else:
|
||||
print '\a'
|
||||
print _msg
|
||||
|
||||
#----------------------------------------------------------------------------
|
109
wxPython/wxPython/lib/sizers/border.py
Normal file
109
wxPython/wxPython/lib/sizers/border.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.sizers.border
|
||||
# Purpose: A Sizer that wraps an empty border around its contents
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 9-June-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1998 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
from sizer import wxSizer
|
||||
|
||||
wxNORTH = 1
|
||||
wxSOUTH = 2
|
||||
wxEAST = 4
|
||||
wxWEST = 8
|
||||
wxALL = wxNORTH | wxSOUTH | wxEAST | wxWEST
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class wxBorderSizer(wxSizer):
|
||||
"""
|
||||
wxBorderSizer
|
||||
|
||||
This sizer provides an empty buffer on one or more sides of it's
|
||||
contents. It can only hold a single widget, but that can be a
|
||||
sizer containing other items if you wish.
|
||||
|
||||
The sizer is constructed with a parameter specifying which sides
|
||||
should have the border. You can use a logical OR of the following
|
||||
values to specify the sides:
|
||||
|
||||
wxNORTH -- the top side
|
||||
wxSOUTH -- the bottom side
|
||||
wxEAST -- the right side
|
||||
wxWEST -- the left side
|
||||
wxALL -- all sides
|
||||
|
||||
The width in pixels of the border is specified when the child
|
||||
widget is Added to the sizer.
|
||||
|
||||
"""
|
||||
def __init__(self, sides = wxALL):
|
||||
wxSizer.__init__(self)
|
||||
self.sides = sides
|
||||
|
||||
|
||||
def Add(self, widget, borderSize):
|
||||
if self.children:
|
||||
raise ValueError("wxBorderSizer can only contain one child.")
|
||||
|
||||
wxSizer.Add(self, widget, borderSize)
|
||||
|
||||
|
||||
def CalcMin(self):
|
||||
isSizer, widget, width, height, borderSize = self.children[0]
|
||||
|
||||
if isSizer:
|
||||
width, height = widget.CalcMin()
|
||||
|
||||
if self.sides & wxEAST:
|
||||
width = width + borderSize
|
||||
|
||||
if self.sides & wxWEST:
|
||||
width = width + borderSize
|
||||
|
||||
if self.sides & wxNORTH:
|
||||
height = height + borderSize
|
||||
|
||||
if self.sides & wxSOUTH:
|
||||
height = height + borderSize
|
||||
|
||||
return width, height
|
||||
|
||||
|
||||
def RecalcSizes(self):
|
||||
isSizer, widget, width, height, borderSize = self.children[0]
|
||||
width = self.size.width
|
||||
height = self.size.height
|
||||
px = self.origin.x
|
||||
py = self.origin.y
|
||||
|
||||
if self.sides & wxWEST:
|
||||
width = width - borderSize
|
||||
px = px + borderSize
|
||||
if self.sides & wxEAST:
|
||||
width = width - borderSize
|
||||
|
||||
if self.sides & wxNORTH:
|
||||
height = height - borderSize
|
||||
py = py + borderSize
|
||||
if self.sides & wxSOUTH:
|
||||
height = height - borderSize
|
||||
|
||||
widget.SetDimensions(px, py, width, height)
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
#
|
||||
# TODO... Make an abstract class wxBorder whose decendants can be added to
|
||||
# a wxBorderSizer to provide drawing for the buffer area. Ideas are
|
||||
# to provide a color border, beveled borders, rounded borders, etc.
|
||||
|
||||
|
||||
|
||||
|
||||
|
137
wxPython/wxPython/lib/sizers/box.py
Normal file
137
wxPython/wxPython/lib/sizers/box.py
Normal file
@@ -0,0 +1,137 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.sizers.box
|
||||
# Purpose: A sizer/layout managers for wxPython that places items in
|
||||
# a stretchable box
|
||||
#
|
||||
# Author: Robin Dunn and Dirk Holtwick
|
||||
#
|
||||
# Created: 17-May-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1998 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
from sizer import wxSizer
|
||||
from wxPython.wx import wxVERTICAL, wxHORIZONTAL
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
class wxBoxSizer(wxSizer):
|
||||
"""
|
||||
wxBoxSizer
|
||||
|
||||
A Sizer that lays components out in a box, in the order they are
|
||||
added to the layout manager, with a given orientation. The
|
||||
orientation is specified in the constructor with either wxVERTICAL
|
||||
or wxHORIZONTAL.
|
||||
|
||||
The optional parameter to the Add method (for this sizer it's
|
||||
called the stretch flag) can be used to flag one or more components
|
||||
as stretchable, meaning that they will expand to fill available
|
||||
space in the given orientation. The default is zero, or not
|
||||
stretchable.
|
||||
|
||||
If the stretch flag is non-zero then the widget will stretch. If
|
||||
the sizer holds more than one item that is stretchable then they
|
||||
share the available space.
|
||||
|
||||
If the strech flag is greater than 1 then it serves as a weighting
|
||||
factor. Widgets with a flag of 2 will get twice as much space as
|
||||
widgets with 1, etc.
|
||||
"""
|
||||
def __init__(self, orientation, size = None):
|
||||
wxSizer.__init__(self, size)
|
||||
self.orientation = orientation
|
||||
|
||||
|
||||
def CalcMin(self):
|
||||
self.stretchable = 0 # number of stretchable items
|
||||
self.minWidth = 0 # minimal size
|
||||
self.minHeight = 0
|
||||
self.fixedWidth = 0 # size without stretched widgets
|
||||
self.fixedHeight = 0
|
||||
|
||||
# iterate through children
|
||||
for (isSizer, widget, width, height, stretch) in self.children:
|
||||
weight = 1
|
||||
if stretch:
|
||||
weight = stretch
|
||||
|
||||
if isSizer:
|
||||
# let sub-sizers recalc their required space
|
||||
width, height = widget.CalcMin()
|
||||
|
||||
# minimal size
|
||||
if self.orientation == wxVERTICAL:
|
||||
self.minHeight = self.minHeight + (height * weight)
|
||||
self.minWidth = max(self.minWidth, width)
|
||||
else:
|
||||
self.minWidth = self.minWidth + (width * weight)
|
||||
self.minHeight = max(self.minHeight, height)
|
||||
|
||||
# stretchable items
|
||||
if stretch:
|
||||
self.stretchable = self.stretchable + weight
|
||||
else:
|
||||
if self.orientation == wxVERTICAL:
|
||||
self.fixedHeight = self.fixedHeight + height
|
||||
self.fixedWidth = max(self.fixedWidth, width)
|
||||
else:
|
||||
self.fixedWidth = self.fixedWidth + width
|
||||
self.fixedHeight = max(self.fixedHeight, height)
|
||||
|
||||
return self.minWidth, self.minHeight
|
||||
|
||||
|
||||
|
||||
def RecalcSizes(self):
|
||||
# get current dimensions, save for performance
|
||||
myWidth = self.size.width
|
||||
myHeight = self.size.height
|
||||
|
||||
# relative recent positions & sizes
|
||||
px = self.origin.x
|
||||
py = self.origin.y
|
||||
newWidth = 0
|
||||
newHeight = 0
|
||||
|
||||
# calculate space for one stretched item
|
||||
if self.stretchable:
|
||||
if self.orientation == wxHORIZONTAL:
|
||||
delta = (myWidth - self.fixedWidth) / self.stretchable
|
||||
extra = (myWidth - self.fixedWidth) % self.stretchable
|
||||
else:
|
||||
delta = (myHeight - self.fixedHeight) / self.stretchable
|
||||
extra = (myHeight - self.fixedHeight) % self.stretchable
|
||||
|
||||
# iterate children ...
|
||||
for (isSizer, widget, width, height, stretch) in self.children:
|
||||
weight = 1
|
||||
if stretch:
|
||||
weight = stretch
|
||||
|
||||
if isSizer:
|
||||
width, height = widget.CalcMin()
|
||||
|
||||
# ... vertical
|
||||
if self.orientation == wxVERTICAL:
|
||||
newHeight = height
|
||||
if stretch:
|
||||
newHeight = (delta * weight) + extra # first stretchable gets extra pixels
|
||||
extra = 0
|
||||
widget.SetDimensions(px, py, myWidth, newHeight)
|
||||
|
||||
# ... horizontal
|
||||
elif self.orientation == wxHORIZONTAL:
|
||||
newWidth = width
|
||||
if stretch:
|
||||
newWidth = (delta * weight) + extra # first stretchable gets extra pixels
|
||||
extra = 0
|
||||
widget.SetDimensions(px, py, newWidth, myHeight)
|
||||
|
||||
px = px + newWidth
|
||||
py = py + newHeight
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
97
wxPython/wxPython/lib/sizers/shape.py
Normal file
97
wxPython/wxPython/lib/sizers/shape.py
Normal file
@@ -0,0 +1,97 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.sizers.shape
|
||||
# Purpose: A Sizer that preserves the shape (proportions)
|
||||
# of the managed window
|
||||
#
|
||||
# Created: 7-October-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: SIA "ANK"
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
from sizer import wxSizer
|
||||
|
||||
wxANCHOR_NONE = 0
|
||||
wxANCHOR_NORTH = 1
|
||||
wxANCHOR_SOUTH = 2
|
||||
wxANCHOR_EAST = 4
|
||||
wxANCHOR_WEST = 8
|
||||
wxANCHOR_NW = wxANCHOR_NORTH | wxANCHOR_WEST
|
||||
wxANCHOR_NE = wxANCHOR_NORTH | wxANCHOR_EAST
|
||||
wxANCHOR_SW = wxANCHOR_SOUTH | wxANCHOR_WEST
|
||||
wxANCHOR_SE = wxANCHOR_SOUTH | wxANCHOR_EAST
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class wxShapeSizer(wxSizer):
|
||||
"""
|
||||
wxShapeSizer
|
||||
|
||||
This sizer preserves the proportional dimensions of the managed
|
||||
window, leaving empty space either in horizontal or vertical
|
||||
dimension.
|
||||
|
||||
By default, the managed window is centered within allowed size.
|
||||
You may specify an anchor parameter to leave all of the extra
|
||||
space on one side: wxANCHOR_NORTH and wxANCHOR_SOUTH manage
|
||||
vertical dimension, leaving extra space on the bottom or top side,
|
||||
respectively; wxANCHOR_EAST and wxANCHOR_WEST do the same in
|
||||
horizontal dimension. wxANCHOR_NW, wxANCHOR_NE, wxANCHOR_SW
|
||||
and wxANCHOR_SE are short-cut names for combinations north+west,
|
||||
north+east, south+west, south+east.
|
||||
|
||||
If both anchors are specified in either direction, south and east
|
||||
take precedence over north and west, respectively. (Because of
|
||||
gravity, widgets tend to fall down.)
|
||||
"""
|
||||
def __init__(self, anchor =wxANCHOR_NONE):
|
||||
wxSizer.__init__(self)
|
||||
self.anchor =anchor
|
||||
|
||||
def Add(self, widget):
|
||||
if self.children:
|
||||
raise ValueError("wxShapeSizer can only contain one child.")
|
||||
|
||||
wxSizer.Add(self, widget)
|
||||
|
||||
def CalcMin(self):
|
||||
isSizer, widget, width, height, borderSize = self.children[0]
|
||||
|
||||
if isSizer:
|
||||
width, height = widget.CalcMin()
|
||||
|
||||
return width, height
|
||||
|
||||
def RecalcSizes(self):
|
||||
isSizer, widget, width, height, borderSize = self.children[0]
|
||||
width =self.size.width
|
||||
height =self.size.height
|
||||
px =self.origin.x
|
||||
py =self.origin.y
|
||||
anchor =self.anchor
|
||||
# get current dimensions of the managed window
|
||||
w, h =self.CalcMin()
|
||||
ratio =float(w) /h
|
||||
# in what direction space should be added:
|
||||
# -1: horisontal
|
||||
# 1: vertical
|
||||
# 0: shape is ok
|
||||
dir =cmp(ratio /width *height, 1)
|
||||
if dir <0:
|
||||
# recalculate width
|
||||
old_width =width
|
||||
width =height *ratio
|
||||
if anchor & wxANCHOR_EAST:
|
||||
px =px +old_width -width
|
||||
elif not (anchor & wxANCHOR_WEST):
|
||||
px =px +(old_width -width) /2
|
||||
elif dir >0:
|
||||
# recalculate height
|
||||
old_height =height
|
||||
height =width /ratio
|
||||
if anchor & wxANCHOR_SOUTH:
|
||||
py =py +old_height -height
|
||||
elif not (anchor & wxANCHOR_NORTH):
|
||||
py =py +(old_height -height) /2
|
||||
|
||||
widget.SetDimensions(px, py, width, height)
|
112
wxPython/wxPython/lib/sizers/sizer.py
Normal file
112
wxPython/wxPython/lib/sizers/sizer.py
Normal file
@@ -0,0 +1,112 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.sizers.sizer
|
||||
# Purpose: General purpose sizer/layout managers for wxPython
|
||||
#
|
||||
# Author: Robin Dunn and Dirk Holtwick
|
||||
#
|
||||
# Created: 17-May-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1998 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
from wxPython.wx import wxPoint, wxSize
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class wxSizer:
|
||||
"""
|
||||
wxSizer
|
||||
|
||||
An abstract base sizer class. A sizer is able to manage the size and
|
||||
layout of windows and/or child sizers.
|
||||
|
||||
Derived classes should implement CalcMin, and RecalcSizes.
|
||||
|
||||
A window or sizer is added to this sizer with the Add method:
|
||||
|
||||
def Add(self, widget, opt=0)
|
||||
|
||||
The meaning of the opt parameter is different for each type of
|
||||
sizer. It may be a single value or a collection of values.
|
||||
"""
|
||||
def __init__(self, size = None):
|
||||
self.children = []
|
||||
self.origin = wxPoint(0, 0)
|
||||
if not size:
|
||||
size = wxSize(0,0)
|
||||
self.size = size
|
||||
|
||||
def Add(self, widget, opt=0):
|
||||
"""
|
||||
Add a window or a sizer to this sizer. The meaning of the opt
|
||||
parameter is different for each type of sizer. It may be a single
|
||||
value or a collection of values.
|
||||
"""
|
||||
size = widget.GetSize()
|
||||
isSizer = isinstance(widget, wxSizer)
|
||||
self.children.append( (isSizer, widget, size.width, size.height, opt) )
|
||||
|
||||
|
||||
def AddMany(self, widgets):
|
||||
"""
|
||||
Add a sequence (list, tuple, etc.) of widgets to this sizer. The
|
||||
items in the sequence should be tuples containing valid args for
|
||||
the Add method.
|
||||
"""
|
||||
for childinfo in widgets:
|
||||
if type(childinfo) != type(()):
|
||||
childinfo = (childinfo, )
|
||||
apply(self.Add, childinfo)
|
||||
|
||||
|
||||
def SetDimensions(self, x, y, width, height):
|
||||
self.origin = wxPoint(x, y)
|
||||
self.size = wxSize(width, height)
|
||||
self.RecalcSizes()
|
||||
|
||||
def GetSize(self):
|
||||
return self.size
|
||||
|
||||
def GetPosition(self):
|
||||
return self.origin
|
||||
|
||||
def CalcMin(self):
|
||||
raise NotImplementedError("Derived class should implement CalcMin")
|
||||
|
||||
def RecalcSizes(self):
|
||||
raise NotImplementedError("Derived class should implement RecalcSizes")
|
||||
|
||||
|
||||
|
||||
def __getMinWindowSize(self, win):
|
||||
"""
|
||||
Calculate the best size window to hold this sizer, taking into
|
||||
account the difference between client size and window size.
|
||||
"""
|
||||
min = self.GetMinSize()
|
||||
a1,a2 = win.GetSizeTuple()
|
||||
b1,b2 = win.GetClientSizeTuple()
|
||||
w = min.width + (a1 - b1)
|
||||
h = min.height + (a2 - b2)
|
||||
return (w, h)
|
||||
|
||||
|
||||
def GetMinSize(self):
|
||||
minWidth, minHeight = self.CalcMin()
|
||||
return wxSize(minWidth, minHeight)
|
||||
|
||||
def SetWindowSizeHints(self, win):
|
||||
w, h = self.__getMinWindowSize(win)
|
||||
win.SetSizeHints(w,h)
|
||||
|
||||
def FitWindow(self, win):
|
||||
w, h = self.__getMinWindowSize(win)
|
||||
win.SetSize(wxSize(w,h))
|
||||
|
||||
def Layout(self, size):
|
||||
self.CalcMin()
|
||||
self.SetDimensions(self.origin.x, self.origin.y,
|
||||
size.width, size.height)
|
||||
|
||||
#----------------------------------------------------------------------
|
122
wxPython/wxPython/lib/splashscreen.py
Normal file
122
wxPython/wxPython/lib/splashscreen.py
Normal file
@@ -0,0 +1,122 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.splashscreen
|
||||
# Purpose: A simple frame that can display a bitmap and closes itself
|
||||
# after a specified timeout or a mouse click.
|
||||
#
|
||||
# Author: Mike Fletcher, Robin Dunn
|
||||
#
|
||||
# Created: 19-Nov-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1999 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
from wxPython.wx import *
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
def bitmapFromFile(filename):
|
||||
'''Non-portable test for bitmap type...'''
|
||||
import imghdr
|
||||
BITMAPTYPEGUESSDICT = {
|
||||
"bmp" :wxBITMAP_TYPE_BMP,
|
||||
"png" :wxBITMAP_TYPE_PNG,
|
||||
"jpeg":wxBITMAP_TYPE_JPEG,
|
||||
"gif" :wxBITMAP_TYPE_GIF,
|
||||
"xbm" :wxBITMAP_TYPE_XBM,
|
||||
}
|
||||
# following assumes bitmap type if we cannot resolve image type
|
||||
typ = BITMAPTYPEGUESSDICT.get(imghdr.what(filename), wxBITMAP_TYPE_BMP)
|
||||
bitmap = wxImage(filename, typ).ConvertToBitmap()
|
||||
return bitmap
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class SplashScreen(wxFrame):
|
||||
def __init__(self, parent, ID=-1, title="SplashScreen",
|
||||
style=wxSIMPLE_BORDER|wxSTAY_ON_TOP,
|
||||
duration=1500, bitmapfile="bitmaps/splashscreen.bmp",
|
||||
callback = None):
|
||||
'''
|
||||
parent, ID, title, style -- see wxFrame
|
||||
duration -- milliseconds to display the splash screen
|
||||
bitmapfile -- absolute or relative pathname, extension used for type negotiation
|
||||
callback -- if specified, is called when timer completes, callback is responsible for closing the splash screen
|
||||
'''
|
||||
### Loading bitmap
|
||||
self.bitmap = bmp = bitmapFromFile(bitmapfile)
|
||||
### Determine size of bitmap to size window...
|
||||
size = (bmp.GetWidth(), bmp.GetHeight())
|
||||
# size of screen
|
||||
width = wxSystemSettings_GetSystemMetric(wxSYS_SCREEN_X)
|
||||
height = wxSystemSettings_GetSystemMetric(wxSYS_SCREEN_Y)
|
||||
pos = ((width-size[0])/2, (height-size[1])/2)
|
||||
|
||||
# check for overflow...
|
||||
if pos[0] < 0:
|
||||
size = (wxSystemSettings_GetSystemMetric(wxSYS_SCREEN_X), size[1])
|
||||
if pos[1] < 0:
|
||||
size = (size[0], wxSystemSettings_GetSystemMetric(wxSYS_SCREEN_Y))
|
||||
|
||||
wxFrame.__init__(self, parent, ID, title, pos, size, style)
|
||||
EVT_LEFT_DOWN(self, self.OnMouseClick)
|
||||
EVT_CLOSE(self, self.OnCloseWindow)
|
||||
EVT_PAINT(self, self.OnPaint)
|
||||
EVT_ERASE_BACKGROUND(self, self.OnEraseBG)
|
||||
|
||||
self.Show(true)
|
||||
#dc = wxClientDC(self)
|
||||
#dc.DrawBitmap(self.bitmap, 0,0, false)
|
||||
|
||||
class SplashTimer(wxTimer):
|
||||
def __init__(self, targetFunction):
|
||||
self.Notify = targetFunction
|
||||
wxTimer.__init__(self)
|
||||
|
||||
if callback is None:
|
||||
callback = self.OnSplashExitDefault
|
||||
|
||||
self.timer = SplashTimer(callback)
|
||||
self.timer.Start(duration, 1) # one-shot only
|
||||
|
||||
def OnPaint(self, event):
|
||||
dc = wxPaintDC(self)
|
||||
dc.DrawBitmap(self.bitmap, 0,0, false)
|
||||
|
||||
def OnEraseBG(self, event):
|
||||
pass
|
||||
|
||||
def OnSplashExitDefault(self, event=None):
|
||||
self.Close(true)
|
||||
|
||||
def OnCloseWindow(self, event=None):
|
||||
self.Show(false)
|
||||
self.timer.Stop()
|
||||
del self.timer
|
||||
self.Destroy()
|
||||
|
||||
def OnMouseClick(self, event):
|
||||
self.timer.Notify()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
class DemoApp(wxApp):
|
||||
def OnInit(self):
|
||||
wxImage_AddHandler(wxJPEGHandler())
|
||||
wxImage_AddHandler(wxPNGHandler())
|
||||
wxImage_AddHandler(wxGIFHandler())
|
||||
self.splash = SplashScreen(NULL, bitmapfile="splashscreen.jpg", callback=self.OnSplashExit)
|
||||
self.splash.Show(true)
|
||||
self.SetTopWindow(self.splash)
|
||||
return true
|
||||
def OnSplashExit(self, event=None):
|
||||
print "Yay! Application callback worked!"
|
||||
self.splash.Close(true)
|
||||
del self.splash
|
||||
### Build working windows here...
|
||||
def test(sceneGraph=None):
|
||||
app = DemoApp(0)
|
||||
app.MainLoop()
|
||||
test()
|
131
wxPython/wxPython/lib/vtk.py
Normal file
131
wxPython/wxPython/lib/vtk.py
Normal file
@@ -0,0 +1,131 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.vtk
|
||||
# Purpose: Provides a wrapper around the vtkRenderWindow from the
|
||||
# VTK Visualization Toolkit. Requires the VTK Python
|
||||
# extensions from http://www.kitware.com/
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 16-Nov-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1999 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
try: # For Win32,
|
||||
from vtkpython import *
|
||||
except ImportError:
|
||||
try: # for Unix. Why they do it this way is anybody's guess...
|
||||
from libVTKCommonPython import *
|
||||
from libVTKGraphicsPython import *
|
||||
from libVTKImagingPython import *
|
||||
except ImportError:
|
||||
raise ImportError, "VTK extension module not found"
|
||||
|
||||
from wxPython.wx import *
|
||||
import math
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class wxVTKRenderWindow(wxScrolledWindow):
|
||||
def __init__(self, parent, id, position=wxDefaultPosition,
|
||||
size=wxDefaultSize, style=0):
|
||||
wxScrolledWindow.__init__(self, parent, id, position, size, style)
|
||||
|
||||
self.renderWindow = vtkRenderWindow()
|
||||
|
||||
if wxPlatform != '__WXMSW__':
|
||||
# We can't get the handle in wxGTK until after the widget
|
||||
# is created, the window create event happens later so we'll
|
||||
# catch it there
|
||||
EVT_WINDOW_CREATE(self, self.OnCreateWindow)
|
||||
else:
|
||||
# but in MSW, the window create event happens durring the above
|
||||
# call to __init__ so we have to do it here.
|
||||
hdl = self.GetHandle()
|
||||
self.renderWindow.SetWindowInfo(str(hdl))
|
||||
|
||||
|
||||
EVT_LEFT_DOWN (self, self.SaveClick)
|
||||
EVT_MIDDLE_DOWN(self, self.SaveClick)
|
||||
EVT_RIGHT_DOWN (self, self.SaveClick)
|
||||
EVT_LEFT_UP (self, self.Release)
|
||||
EVT_MIDDLE_UP (self, self.Release)
|
||||
EVT_RIGHT_UP (self, self.Release)
|
||||
EVT_MOTION (self, self.MouseMotion)
|
||||
|
||||
EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
|
||||
EVT_PAINT(self, self.OnPaint)
|
||||
|
||||
|
||||
def GetRenderer(self):
|
||||
self.renderWindow.GetRenderers().InitTraversal()
|
||||
return self.renderWindow.GetRenderers().GetNextItem()
|
||||
|
||||
|
||||
def GetRenderWindow(self):
|
||||
return self.renderWindow
|
||||
|
||||
|
||||
def OnPaint(self, event):
|
||||
dc = wxPaintDC(self)
|
||||
self.renderWindow.Render()
|
||||
|
||||
def OnCreateWindow(self, event):
|
||||
hdl = self.GetHandle()
|
||||
self.renderWindow.SetWindowInfo(str(hdl))
|
||||
|
||||
def OnEraseBackground(self, event):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def SaveClick(self, event):
|
||||
self.prev_x, self.prev_y = event.GetPositionTuple()
|
||||
self.CaptureMouse()
|
||||
|
||||
def Release(self, event):
|
||||
self.ReleaseMouse()
|
||||
|
||||
def MouseMotion(self, event):
|
||||
event.x, event.y = event.GetPositionTuple()
|
||||
size = self.GetClientSize()
|
||||
if event.LeftIsDown():
|
||||
# rotate
|
||||
camera = self.GetRenderer().GetActiveCamera()
|
||||
camera.Azimuth(float(self.prev_x - event.x) / size.width * 360)
|
||||
camera.Elevation(float(event.y - self.prev_y) / size.width * 360)
|
||||
camera.OrthogonalizeViewUp()
|
||||
self.MotionUpdate(event)
|
||||
|
||||
elif event.MiddleIsDown():
|
||||
# pan
|
||||
camera = self.GetRenderer().GetActiveCamera()
|
||||
camera.Yaw(-float(self.prev_x - event.x) / size.width * 30)
|
||||
camera.Pitch(float(event.y - self.prev_y) / size.width * 30)
|
||||
camera.OrthogonalizeViewUp()
|
||||
self.MotionUpdate(event)
|
||||
|
||||
elif event.RightIsDown():
|
||||
# dolly
|
||||
camera = self.GetRenderer().GetActiveCamera()
|
||||
camera.Dolly(math.exp(float((event.x - self.prev_x) - \
|
||||
(event.y - self.prev_y))/ \
|
||||
size.width))
|
||||
self.MotionUpdate(event)
|
||||
|
||||
|
||||
def MotionUpdate(self,event):
|
||||
renderer = self.GetRenderer()
|
||||
renderer.GetLights().InitTraversal()
|
||||
light = renderer.GetLights().GetNextItem()
|
||||
camera = renderer.GetActiveCamera()
|
||||
light.SetPosition(camera.GetPosition())
|
||||
light.SetFocalPoint(camera.GetFocalPoint())
|
||||
self.renderWindow.Render()
|
||||
self.prev_x = event.x
|
||||
self.prev_y = event.y
|
||||
|
||||
|
||||
|
466
wxPython/wxPython/lib/wxPlotCanvas.py
Normal file
466
wxPython/wxPython/lib/wxPlotCanvas.py
Normal file
@@ -0,0 +1,466 @@
|
||||
"""
|
||||
This is a port of Konrad Hinsen's tkPlotCanvas.py plotting module.
|
||||
After thinking long and hard I came up with the name "wxPlotCanvas.py".
|
||||
|
||||
This file contains two parts; first the re-usable library stuff, then, after
|
||||
a "if __name__=='__main__'" test, a simple frame and a few default plots
|
||||
for testing.
|
||||
|
||||
Harm van der Heijden, feb 1999
|
||||
|
||||
Original comment follows below:
|
||||
# This module defines a plot widget for Tk user interfaces.
|
||||
# It supports only elementary line plots at the moment.
|
||||
# See the example at the end for documentation...
|
||||
#
|
||||
# Written by Konrad Hinsen <hinsen@cnrs-orleans.fr>
|
||||
# With contributions from RajGopal Srinivasan <raj@cherubino.med.jhmi.edu>
|
||||
# Last revision: 1998-7-28
|
||||
#
|
||||
"""
|
||||
|
||||
from wxPython import wx
|
||||
import string
|
||||
|
||||
# Not everybody will have Numeric, so let's be cool about it...
|
||||
try:
|
||||
import Numeric
|
||||
except:
|
||||
# bummer!
|
||||
d = wx.wxMessageDialog(wx.NULL,
|
||||
"""This module requires the Numeric module, which could not be imported.
|
||||
It probably is not installed (it's not part of the standard Python
|
||||
distribution). See the Python site (http://www.python.org) for
|
||||
information on downloading source or binaries.""",
|
||||
"Numeric not found")
|
||||
if d.ShowModal() == wx.wxID_CANCEL:
|
||||
d = wx.wxMessageDialog(wx.NULL, "I kid you not! Pressing Cancel won't help you!", "Not a joke", wx.wxOK)
|
||||
d.ShowModal()
|
||||
raise ImportError
|
||||
|
||||
#
|
||||
# Plotting classes...
|
||||
#
|
||||
class PolyPoints:
|
||||
|
||||
def __init__(self, points, attr):
|
||||
self.points = Numeric.array(points)
|
||||
self.scaled = self.points
|
||||
self.attributes = {}
|
||||
for name, value in self._attributes.items():
|
||||
try:
|
||||
value = attr[name]
|
||||
except KeyError: pass
|
||||
self.attributes[name] = value
|
||||
|
||||
def boundingBox(self):
|
||||
return Numeric.minimum.reduce(self.points), \
|
||||
Numeric.maximum.reduce(self.points)
|
||||
|
||||
def scaleAndShift(self, scale=1, shift=0):
|
||||
self.scaled = scale*self.points+shift
|
||||
|
||||
|
||||
class PolyLine(PolyPoints):
|
||||
|
||||
def __init__(self, points, **attr):
|
||||
PolyPoints.__init__(self, points, attr)
|
||||
|
||||
_attributes = {'color': 'black',
|
||||
'width': 1}
|
||||
|
||||
def draw(self, dc):
|
||||
color = self.attributes['color']
|
||||
width = self.attributes['width']
|
||||
arguments = []
|
||||
dc.SetPen(wx.wxPen(wx.wxNamedColour(color), width))
|
||||
dc.DrawLines(map(tuple,self.scaled))
|
||||
|
||||
|
||||
class PolyMarker(PolyPoints):
|
||||
|
||||
def __init__(self, points, **attr):
|
||||
|
||||
PolyPoints.__init__(self, points, attr)
|
||||
|
||||
_attributes = {'color': 'black',
|
||||
'width': 1,
|
||||
'fillcolor': None,
|
||||
'size': 2,
|
||||
'fillstyle': wx.wxSOLID,
|
||||
'outline': 'black',
|
||||
'marker': 'circle'}
|
||||
|
||||
def draw(self, dc):
|
||||
color = self.attributes['color']
|
||||
width = self.attributes['width']
|
||||
size = self.attributes['size']
|
||||
fillcolor = self.attributes['fillcolor']
|
||||
fillstyle = self.attributes['fillstyle']
|
||||
marker = self.attributes['marker']
|
||||
|
||||
dc.SetPen(wx.wxPen(wx.wxNamedColour(color),width))
|
||||
if fillcolor:
|
||||
dc.SetBrush(wx.wxBrush(wx.wxNamedColour(fillcolor),fillstyle))
|
||||
else:
|
||||
dc.SetBrush(wx.wxBrush(wx.wxNamedColour('black'), wx.wxTRANSPARENT))
|
||||
|
||||
self._drawmarkers(dc, self.scaled, marker, size)
|
||||
|
||||
def _drawmarkers(self, dc, coords, marker,size=1):
|
||||
f = eval('self._' +marker)
|
||||
for xc, yc in coords:
|
||||
f(dc, xc, yc, size)
|
||||
|
||||
def _circle(self, dc, xc, yc, size=1):
|
||||
dc.DrawEllipse(xc-2.5*size,yc-2.5*size,5.*size,5.*size)
|
||||
|
||||
def _dot(self, dc, xc, yc, size=1):
|
||||
dc.DrawPoint(xc,yc)
|
||||
|
||||
def _square(self, dc, xc, yc, size=1):
|
||||
dc.DrawRectangle(xc-2.5*size,yc-2.5*size,5.*size,5.*size)
|
||||
|
||||
def _triangle(self, dc, xc, yc, size=1):
|
||||
dc.DrawPolygon([(-0.5*size*5,0.2886751*size*5),
|
||||
(0.5*size*5,0.2886751*size*5),
|
||||
(0.0,-0.577350*size*5)],xc,yc)
|
||||
|
||||
def _triangle_down(self, dc, xc, yc, size=1):
|
||||
dc.DrawPolygon([(-0.5*size*5,-0.2886751*size*5),
|
||||
(0.5*size*5,-0.2886751*size*5),
|
||||
(0.0,0.577350*size*5)],xc,yc)
|
||||
|
||||
def _cross(self, dc, xc, yc, size=1):
|
||||
dc.DrawLine(xc-2.5*size,yc-2.5*size,xc+2.5*size,yc+2.5*size)
|
||||
dc.DrawLine(xc-2.5*size,yc+2.5*size,xc+2.5*size,yc-2.5*size)
|
||||
|
||||
def _plus(self, dc, xc, yc, size=1):
|
||||
dc.DrawLine(xc-2.5*size,yc,xc+2.5*size,yc)
|
||||
dc.DrawLine(xc,yc-2.5*size,xc,yc+2.5*size)
|
||||
|
||||
class PlotGraphics:
|
||||
|
||||
def __init__(self, objects):
|
||||
self.objects = objects
|
||||
|
||||
def boundingBox(self):
|
||||
p1, p2 = self.objects[0].boundingBox()
|
||||
for o in self.objects[1:]:
|
||||
p1o, p2o = o.boundingBox()
|
||||
p1 = Numeric.minimum(p1, p1o)
|
||||
p2 = Numeric.maximum(p2, p2o)
|
||||
return p1, p2
|
||||
|
||||
def scaleAndShift(self, scale=1, shift=0):
|
||||
for o in self.objects:
|
||||
o.scaleAndShift(scale, shift)
|
||||
|
||||
def draw(self, canvas):
|
||||
for o in self.objects:
|
||||
o.draw(canvas)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.objects)
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.objects[item]
|
||||
|
||||
|
||||
class PlotCanvas(wx.wxWindow):
|
||||
|
||||
def __init__(self, parent, id = -1):
|
||||
wx.wxWindow.__init__(self, parent, id, wx.wxPyDefaultPosition, wx.wxPyDefaultSize)
|
||||
self.border = (1,1)
|
||||
self.SetClientSizeWH(400,400)
|
||||
self.SetBackgroundColour(wx.wxNamedColour("white"))
|
||||
|
||||
wx.EVT_SIZE(self,self.reconfigure)
|
||||
wx.EVT_PAINT(self, self.OnPaint)
|
||||
self._setsize()
|
||||
self.last_draw = None
|
||||
# self.font = self._testFont(font)
|
||||
|
||||
def OnPaint(self, event):
|
||||
pdc = wx.wxPaintDC(self)
|
||||
if self.last_draw is not None:
|
||||
apply(self.draw, self.last_draw + (pdc,))
|
||||
|
||||
def reconfigure(self, event):
|
||||
(new_width,new_height) = self.GetClientSizeTuple()
|
||||
if new_width == self.width and new_height == self.height:
|
||||
return
|
||||
self._setsize()
|
||||
# self.redraw()
|
||||
|
||||
def _testFont(self, font):
|
||||
if font is not None:
|
||||
bg = self.canvas.cget('background')
|
||||
try:
|
||||
item = CanvasText(self.canvas, 0, 0, anchor=NW,
|
||||
text='0', fill=bg, font=font)
|
||||
self.canvas.delete(item)
|
||||
except TclError:
|
||||
font = None
|
||||
return font
|
||||
|
||||
def _setsize(self):
|
||||
(self.width,self.height) = self.GetClientSizeTuple();
|
||||
self.plotbox_size = 0.97*Numeric.array([self.width, -self.height])
|
||||
xo = 0.5*(self.width-self.plotbox_size[0])
|
||||
yo = self.height-0.5*(self.height+self.plotbox_size[1])
|
||||
self.plotbox_origin = Numeric.array([xo, yo])
|
||||
|
||||
def draw(self, graphics, xaxis = None, yaxis = None, dc = None):
|
||||
if dc == None: dc = wx.wxClientDC(self)
|
||||
dc.BeginDrawing()
|
||||
dc.Clear()
|
||||
self.last_draw = (graphics, xaxis, yaxis)
|
||||
p1, p2 = graphics.boundingBox()
|
||||
xaxis = self._axisInterval(xaxis, p1[0], p2[0])
|
||||
yaxis = self._axisInterval(yaxis, p1[1], p2[1])
|
||||
text_width = [0., 0.]
|
||||
text_height = [0., 0.]
|
||||
if xaxis is not None:
|
||||
p1[0] = xaxis[0]
|
||||
p2[0] = xaxis[1]
|
||||
xticks = self._ticks(xaxis[0], xaxis[1])
|
||||
bb = dc.GetTextExtent(xticks[0][1])
|
||||
text_height[1] = bb[1]
|
||||
text_width[0] = 0.5*bb[0]
|
||||
bb = dc.GetTextExtent(xticks[-1][1])
|
||||
text_width[1] = 0.5*bb[0]
|
||||
else:
|
||||
xticks = None
|
||||
if yaxis is not None:
|
||||
p1[1] = yaxis[0]
|
||||
p2[1] = yaxis[1]
|
||||
yticks = self._ticks(yaxis[0], yaxis[1])
|
||||
for y in yticks:
|
||||
bb = dc.GetTextExtent(y[1])
|
||||
text_width[0] = max(text_width[0],bb[0])
|
||||
h = 0.5*bb[1]
|
||||
text_height[0] = h
|
||||
text_height[1] = max(text_height[1], h)
|
||||
else:
|
||||
yticks = None
|
||||
text1 = Numeric.array([text_width[0], -text_height[1]])
|
||||
text2 = Numeric.array([text_width[1], -text_height[0]])
|
||||
scale = (self.plotbox_size-text1-text2) / (p2-p1)
|
||||
shift = -p1*scale + self.plotbox_origin + text1
|
||||
self._drawAxes(dc, xaxis, yaxis, p1, p2,
|
||||
scale, shift, xticks, yticks)
|
||||
graphics.scaleAndShift(scale, shift)
|
||||
graphics.draw(dc)
|
||||
dc.EndDrawing()
|
||||
|
||||
def _axisInterval(self, spec, lower, upper):
|
||||
if spec is None:
|
||||
return None
|
||||
if spec == 'minimal':
|
||||
if lower == upper:
|
||||
return lower-0.5, upper+0.5
|
||||
else:
|
||||
return lower, upper
|
||||
if spec == 'automatic':
|
||||
range = upper-lower
|
||||
if range == 0.:
|
||||
return lower-0.5, upper+0.5
|
||||
log = Numeric.log10(range)
|
||||
power = Numeric.floor(log)
|
||||
fraction = log-power
|
||||
if fraction <= 0.05:
|
||||
power = power-1
|
||||
grid = 10.**power
|
||||
lower = lower - lower % grid
|
||||
mod = upper % grid
|
||||
if mod != 0:
|
||||
upper = upper - mod + grid
|
||||
return lower, upper
|
||||
if type(spec) == type(()):
|
||||
lower, upper = spec
|
||||
if lower <= upper:
|
||||
return lower, upper
|
||||
else:
|
||||
return upper, lower
|
||||
raise ValueError, str(spec) + ': illegal axis specification'
|
||||
|
||||
def _drawAxes(self, dc, xaxis, yaxis,
|
||||
bb1, bb2, scale, shift, xticks, yticks):
|
||||
dc.SetPen(wx.wxPen(wx.wxNamedColour('BLACK'),1))
|
||||
if xaxis is not None:
|
||||
lower, upper = xaxis
|
||||
text = 1
|
||||
for y, d in [(bb1[1], -3), (bb2[1], 3)]:
|
||||
p1 = scale*Numeric.array([lower, y])+shift
|
||||
p2 = scale*Numeric.array([upper, y])+shift
|
||||
dc.DrawLine(p1[0],p1[1],p2[0],p2[1])
|
||||
for x, label in xticks:
|
||||
p = scale*Numeric.array([x, y])+shift
|
||||
dc.DrawLine(p[0],p[1],p[0],p[1]+d)
|
||||
if text:
|
||||
dc.DrawText(label,p[0],p[1])
|
||||
text = 0
|
||||
|
||||
if yaxis is not None:
|
||||
lower, upper = yaxis
|
||||
text = 1
|
||||
h = dc.GetCharHeight()
|
||||
for x, d in [(bb1[0], -3), (bb2[0], 3)]:
|
||||
p1 = scale*Numeric.array([x, lower])+shift
|
||||
p2 = scale*Numeric.array([x, upper])+shift
|
||||
dc.DrawLine(p1[0],p1[1],p2[0],p2[1])
|
||||
for y, label in yticks:
|
||||
p = scale*Numeric.array([x, y])+shift
|
||||
dc.DrawLine(p[0],p[1],p[0]-d,p[1])
|
||||
if text:
|
||||
dc.DrawText(label,p[0]-dc.GetTextExtent(label)[0],
|
||||
p[1]-0.5*h)
|
||||
text = 0
|
||||
|
||||
def _ticks(self, lower, upper):
|
||||
ideal = (upper-lower)/7.
|
||||
log = Numeric.log10(ideal)
|
||||
power = Numeric.floor(log)
|
||||
fraction = log-power
|
||||
factor = 1.
|
||||
error = fraction
|
||||
for f, lf in self._multiples:
|
||||
e = Numeric.fabs(fraction-lf)
|
||||
if e < error:
|
||||
error = e
|
||||
factor = f
|
||||
grid = factor * 10.**power
|
||||
if power > 3 or power < -3:
|
||||
format = '%+7.0e'
|
||||
elif power >= 0:
|
||||
digits = max(1, int(power))
|
||||
format = '%' + `digits`+'.0f'
|
||||
else:
|
||||
digits = -int(power)
|
||||
format = '%'+`digits+2`+'.'+`digits`+'f'
|
||||
ticks = []
|
||||
t = -grid*Numeric.floor(-lower/grid)
|
||||
while t <= upper:
|
||||
ticks.append(t, format % (t,))
|
||||
t = t + grid
|
||||
return ticks
|
||||
|
||||
_multiples = [(2., Numeric.log10(2.)), (5., Numeric.log10(5.))]
|
||||
|
||||
def redraw(self,dc=None):
|
||||
if self.last_draw is not None:
|
||||
apply(self.draw, self.last_draw + (dc,))
|
||||
|
||||
def clear(self):
|
||||
self.canvas.delete('all')
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# if running standalone...
|
||||
#
|
||||
# ...a sample implementation using the above
|
||||
#
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def _InitObjects():
|
||||
# 100 points sin function, plotted as green circles
|
||||
data1 = 2.*Numeric.pi*Numeric.arange(200)/200.
|
||||
data1.shape = (100, 2)
|
||||
data1[:,1] = Numeric.sin(data1[:,0])
|
||||
markers1 = PolyMarker(data1, color='green', marker='circle',size=1)
|
||||
|
||||
# 50 points cos function, plotted as red line
|
||||
data1 = 2.*Numeric.pi*Numeric.arange(100)/100.
|
||||
data1.shape = (50,2)
|
||||
data1[:,1] = Numeric.cos(data1[:,0])
|
||||
lines = PolyLine(data1, color='red')
|
||||
|
||||
# A few more points...
|
||||
pi = Numeric.pi
|
||||
markers2 = PolyMarker([(0., 0.), (pi/4., 1.), (pi/2, 0.),
|
||||
(3.*pi/4., -1)], color='blue',
|
||||
fillcolor='green', marker='cross')
|
||||
|
||||
return PlotGraphics([markers1, lines, markers2])
|
||||
|
||||
|
||||
class AppFrame(wx.wxFrame):
|
||||
def __init__(self, parent, id, title):
|
||||
wx.wxFrame.__init__(self, parent, id, title,
|
||||
wx.wxPyDefaultPosition, wx.wxSize(400, 400))
|
||||
|
||||
# Now Create the menu bar and items
|
||||
self.mainmenu = wx.wxMenuBar()
|
||||
|
||||
menu = wx.wxMenu()
|
||||
menu.Append(200, '&Print...', 'Print the current plot')
|
||||
wx.EVT_MENU(self, 200, self.OnFilePrint)
|
||||
menu.Append(209, 'E&xit', 'Enough of this already!')
|
||||
wx.EVT_MENU(self, 209, self.OnFileExit)
|
||||
self.mainmenu.Append(menu, '&File')
|
||||
|
||||
menu = wx.wxMenu()
|
||||
menu.Append(210, '&Draw', 'Draw plots')
|
||||
wx.EVT_MENU(self,210,self.OnPlotDraw)
|
||||
menu.Append(211, '&Redraw', 'Redraw plots')
|
||||
wx.EVT_MENU(self,211,self.OnPlotRedraw)
|
||||
menu.Append(212, '&Clear', 'Clear canvas')
|
||||
wx.EVT_MENU(self,212,self.OnPlotClear)
|
||||
self.mainmenu.Append(menu, '&Plot')
|
||||
|
||||
menu = wx.wxMenu()
|
||||
menu.Append(220, '&About', 'About this thing...')
|
||||
wx.EVT_MENU(self, 220, self.OnHelpAbout)
|
||||
self.mainmenu.Append(menu, '&Help')
|
||||
|
||||
self.SetMenuBar(self.mainmenu)
|
||||
|
||||
# A status bar to tell people what's happening
|
||||
self.CreateStatusBar(1)
|
||||
|
||||
self.client = PlotCanvas(self)
|
||||
|
||||
def OnFilePrint(self, event):
|
||||
d = wx.wxMessageDialog(self,
|
||||
"""As of this writing, printing support in wxPython is shaky at best.
|
||||
Are you sure you want to do this?""", "Danger!", wx.wxYES_NO)
|
||||
if d.ShowModal() == wx.wxID_YES:
|
||||
psdc = wx.wxPostScriptDC("out.ps", wx.TRUE, self)
|
||||
self.client.redraw(psdc)
|
||||
|
||||
def OnFileExit(self, event):
|
||||
self.Close()
|
||||
|
||||
def OnPlotDraw(self, event):
|
||||
self.client.draw(_InitObjects(),'automatic','automatic');
|
||||
|
||||
def OnPlotRedraw(self,event):
|
||||
self.client.redraw()
|
||||
|
||||
def OnPlotClear(self,event):
|
||||
self.client.last_draw = None
|
||||
dc = wx.wxClientDC(self.client)
|
||||
dc.Clear()
|
||||
|
||||
def OnHelpAbout(self, event):
|
||||
about = wx.wxMessageDialog(self, __doc__, "About...", wx.wxOK)
|
||||
about.ShowModal()
|
||||
|
||||
|
||||
|
||||
class MyApp(wx.wxApp):
|
||||
def OnInit(self):
|
||||
frame = AppFrame(wx.NULL, -1, "wxPlotCanvas")
|
||||
frame.Show(wx.TRUE)
|
||||
self.SetTopWindow(frame)
|
||||
return wx.TRUE
|
||||
|
||||
|
||||
app = MyApp(0)
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
281
wxPython/wxPython/lib/wxpTag.py
Normal file
281
wxPython/wxPython/lib/wxpTag.py
Normal file
@@ -0,0 +1,281 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.wxpTag
|
||||
# Purpose: A wxHtmlTagHandler that knows how to build and place
|
||||
# wxPython widgets onto web pages.
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 13-Sept-1999
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 1999 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
'''
|
||||
wxPython.lib.wxpTag
|
||||
|
||||
This module contains a wxHtmlTagHandler that knows how to build
|
||||
and place wxPython widgets onto wxHtmlWindow web pages.
|
||||
|
||||
You don\'t need to use anything in this module directly, just
|
||||
importing it will create the tag handler and add it to any
|
||||
wxHtmlWinParsers created from that time forth.
|
||||
|
||||
Tags of the following form are recognised:
|
||||
|
||||
<WXP class="classname" [module="modulename"] [width="num"] [height="num"]>
|
||||
<PARAM name="parameterName" value="parameterValue>
|
||||
...
|
||||
</WXP>
|
||||
|
||||
where modulename is the name of a module (possibly in package
|
||||
notation) to import and classname is the name of a class in that
|
||||
module to create an instance of. If the module tag-attribute is not
|
||||
given or is an empty string, then wxPython.wx is used. The width and
|
||||
height attributes are expected to be integers and will be passed to
|
||||
the __init__ method of the class as a wxSize object named size.
|
||||
However, if the width attribute ends with the percent (%) symbol then
|
||||
the value will be used as a percentage of the available width and the
|
||||
wxHtmlWindow will manage the size.
|
||||
|
||||
The name-value pairs in all the nested PARAM tags are packaged up as
|
||||
strings into a python dictionary and passed to the __init__ method of
|
||||
the class as keyword arguments. This means that they are all
|
||||
accessible from the __init__ method as regular parameters, or you use
|
||||
the special Python **kw syntax in your __init__ method to get the
|
||||
dictionary directly.
|
||||
|
||||
Some parameter values are special and if they are present then they will
|
||||
be converted from strings to alternate datatypes. They are:
|
||||
|
||||
id If the value of id can be converted to an integer, it will
|
||||
be. Otherwise it is assumed to be the name of an integer
|
||||
variable in the module.
|
||||
|
||||
colours Any value of the form "#123ABC" will automatically be
|
||||
converted to a wxColour object.
|
||||
|
||||
Py Types Any value begining with "(", "[" or "{" are expected to
|
||||
be a Python tuple, list, or dictionary and eval()
|
||||
will be used to convert them to that type. If the
|
||||
eval() fails then the original string value will be
|
||||
preserved.
|
||||
|
||||
wx Types Any value begining with "wx" is expected to be an attempt
|
||||
to create a wxPython object, such as a wxSize, etc.
|
||||
The eval() will be used to try and construct the
|
||||
object and if it fails then the original string value
|
||||
will be used instead.
|
||||
|
||||
An example:
|
||||
|
||||
<wxp module="" class="wxButton">
|
||||
<param name="label" value="Click here">
|
||||
<param name="id" value="wxID_OK">
|
||||
</wxp>
|
||||
|
||||
Both the begining and ending WXP tags are required.
|
||||
|
||||
In the future support will be added for another tag that can be
|
||||
embedded between the two begining and ending WXP tags and will
|
||||
facilitate calling methods of the widget to help initialize it.
|
||||
Additionally, support may be added to fetch the module from a web
|
||||
server as is done with java applets.
|
||||
|
||||
'''
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
from wxPython.wx import *
|
||||
from wxPython.html import *
|
||||
import wxPython.wx
|
||||
|
||||
import string
|
||||
import types
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
WXPTAG = 'WXP'
|
||||
PARAMTAG = 'PARAM'
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
class wxpTagHandler(wxHtmlWinTagHandler):
|
||||
def __init__(self):
|
||||
wxHtmlWinTagHandler.__init__(self)
|
||||
self.ctx = None
|
||||
|
||||
def GetSupportedTags(self):
|
||||
return WXPTAG+','+PARAMTAG
|
||||
|
||||
|
||||
def HandleTag(self, tag):
|
||||
name = tag.GetName()
|
||||
if name == WXPTAG:
|
||||
return self.HandleWxpTag(tag)
|
||||
elif name == PARAMTAG:
|
||||
return self.HandleParamTag(tag)
|
||||
else:
|
||||
raise ValueError, 'unknown tag: ' + name
|
||||
|
||||
|
||||
def HandleWxpTag(self, tag):
|
||||
if tag.IsEnding():
|
||||
return false
|
||||
|
||||
# create a new context object
|
||||
self.ctx = _Context()
|
||||
|
||||
# find and import the module
|
||||
modName = ''
|
||||
if tag.HasParam('MODULE'):
|
||||
modName = tag.GetParam('MODULE')
|
||||
if modName:
|
||||
self.ctx.classMod = _my_import(modName)
|
||||
else:
|
||||
self.ctx.classMod = wxPython.wx
|
||||
|
||||
# find and verify the class
|
||||
if not tag.HasParam('CLASS'):
|
||||
raise AttributeError, "WXP tag requires a CLASS attribute"
|
||||
|
||||
className = tag.GetParam('CLASS')
|
||||
self.ctx.classObj = getattr(self.ctx.classMod, className)
|
||||
if type(self.ctx.classObj) != types.ClassType:
|
||||
raise TypeError, "WXP tag attribute CLASS must name a class"
|
||||
|
||||
|
||||
|
||||
# now look for width and height
|
||||
width = -1
|
||||
height = -1
|
||||
if tag.HasParam('WIDTH'):
|
||||
width = tag.GetParam('WIDTH')
|
||||
if width[-1] == '%':
|
||||
self.ctx.floatWidth = string.atoi(width[:-1], 0)
|
||||
width = self.ctx.floatWidth
|
||||
else:
|
||||
width = string.atoi(width)
|
||||
if tag.HasParam('HEIGHT'):
|
||||
height = string.atoi(tag.GetParam('HEIGHT'))
|
||||
self.ctx.kwargs['size'] = wxSize(width, height)
|
||||
|
||||
|
||||
self.ParseInner(tag)
|
||||
|
||||
# create the object
|
||||
parent = self.GetParser().GetWindow()
|
||||
if parent:
|
||||
obj = apply(self.ctx.classObj,
|
||||
(parent,),
|
||||
self.ctx.kwargs)
|
||||
obj.Show(true)
|
||||
|
||||
# add it to the HtmlWindow
|
||||
self.GetParser().GetContainer().InsertCell(wxHtmlWidgetCell(obj, self.ctx.floatWidth))
|
||||
self.ctx = None
|
||||
|
||||
return true
|
||||
|
||||
|
||||
|
||||
|
||||
def HandleParamTag(self, tag):
|
||||
if tag.IsEnding():
|
||||
return false
|
||||
|
||||
if not tag.HasParam('NAME'):
|
||||
return false
|
||||
|
||||
name = tag.GetParam('NAME')
|
||||
value = ""
|
||||
if tag.HasParam('VALUE'):
|
||||
value = tag.GetParam('VALUE')
|
||||
|
||||
# check for a param named 'id'
|
||||
if name == 'id':
|
||||
theID = -1
|
||||
try:
|
||||
theID = string.atoi(value)
|
||||
except ValueError:
|
||||
theID = getattr(self.ctx.classMod, value)
|
||||
value = theID
|
||||
|
||||
|
||||
# check for something that should be evaluated
|
||||
elif value[0] in '[{(' or value[:2] == 'wx':
|
||||
saveVal = value
|
||||
try:
|
||||
value = eval(value, self.ctx.classMod.__dict__)
|
||||
except:
|
||||
value = saveVal
|
||||
|
||||
# convert to wxColour
|
||||
elif value[0] == '#':
|
||||
try:
|
||||
red = string.atoi('0x'+value[1:3], 16)
|
||||
green = string.atoi('0x'+value[3:5], 16)
|
||||
blue = string.atoi('0x'+value[5:], 16)
|
||||
value = wxColor(red, green, blue)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.ctx.kwargs[name] = value
|
||||
return false
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# just a place to hold some values
|
||||
class _Context:
|
||||
def __init__(self):
|
||||
self.kwargs = {}
|
||||
self.width = -1
|
||||
self.height = -1
|
||||
self.classMod = None
|
||||
self.classObj = None
|
||||
self.floatWidth = 0
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Function to assist with importing packages
|
||||
def _my_import(name):
|
||||
mod = __import__(name)
|
||||
components = string.split(name, '.')
|
||||
for comp in components[1:]:
|
||||
mod = getattr(mod, comp)
|
||||
return mod
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Function to parse a param string (of the form 'item=value item2="value etc"'
|
||||
# and creates a dictionary
|
||||
def _param2dict(param):
|
||||
i = 0; j = 0; s = len(param); d = {}
|
||||
while 1:
|
||||
while i<s and param[i] == " " : i = i+1
|
||||
if i>=s: break
|
||||
j = i
|
||||
while j<s and param[j] != "=": j=j+1
|
||||
if j+1>=s:
|
||||
break
|
||||
word = param[i:j]
|
||||
i=j+1
|
||||
if (param[i] == '"'):
|
||||
j=i+1
|
||||
while j<s and param[j] != '"' : j=j+1
|
||||
if j == s: break
|
||||
val = param[i+1:j]
|
||||
elif (param[i] != " "):
|
||||
j=i+1
|
||||
while j<s and param[j] != " " : j=j+1
|
||||
val = param[i:j]
|
||||
else:
|
||||
val = ""
|
||||
i=j+1
|
||||
d[word] = val
|
||||
return d
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
wxHtmlWinParser_AddTagHandler(wxpTagHandler)
|
Reference in New Issue
Block a user