00001 ################################# 00002 # Miniature window module # 00003 ################################# 00004 # This module and its two classes are responsible for showing the miniature window of the visual window. 00005 00006 from qt import * 00007 from visWindow import * # We need to import this module to get the rest of the imports from cdbVis. We cannot import cdbVis because this module will try to initialize the SystemWindow class before it is available 00008 00009 00010 ########################################################################## 00011 # SystemWindow class ## 00012 ########################################################################## 00013 00014 #CONSTANTS - for this class; GUI constants that does not make sense to collect with all the others in CdbVisCore 00015 SYSTEM_PANEL = 6001 00016 SYSTEM_WINDOW_HEIGHT = 200 00017 SYSTEM_WINDOW_WIDTH = 200 00018 00019 ## 00020 # This class is responsible for displaying the window with the Miniature Window inside; 00021 # which shows the whole visual window in a miniature size (zoomed out). The window will 00022 # stay on top of the parent window, but it is not modal; it floats on top of it as what 00023 # you are used to with floating tool bars. 00024 # 00025 # TODO: At the moment it does only make sense to show this window if we are in the 00026 # device level, but at the moment it is shown for every level...but only showing objects 00027 # when in device level. 00028 # 00029 # Inherits wxMiniFrame for the graphical display, and dbUpdate (implements the interface) 00030 # to include the methods included in that class. 00031 # 00032 # 00033 class SystemWindow(QDialog ,dbUpdate): #wxMiniFrame, dbUpdate): 00034 00035 # Constructor 00036 ## 00037 # The constructor: Initializes the System Window. 00038 # 00039 # Parameters: 00040 # @self - the instance object of this class 00041 # @parent - the parent window (usually mainWindow) 00042 # TURNING OBSELETE -> @id - ID of _this_ window, that the parent sets 00043 # @main - Our communication object (mainWindow) 00044 # 00045 def __init__(self, main, parent): 00046 00047 # We get the size and position of the parent window, so that we can position this window 00048 # relative to that; we put it close to the bottom right corner of the parent window. 00049 parent_pos = main.pos() #main.GetPosition() 00050 parent_size = main.size() #main.GetSize() 00051 00052 # Call the constructor to wxMiniFrame which we inherit from; so that our window can be drawn as a frame. 00053 #wxMiniFrame.__init__(self, parent, id, "Miniature Window",pos=wxPoint(parent_pos.x+parent_size.GetWidth()-SYSTEM_WINDOW_WIDTH,parent_pos.y+parent_size.GetHeight()-SYSTEM_WINDOW_HEIGHT),size=wxSize(SYSTEM_WINDOW_WIDTH,SYSTEM_WINDOW_HEIGHT),style=wxDEFAULT_FRAME_STYLE) 00054 QDialog.__init__(self, parent) 00055 00056 # Set the communication object to a member variable so that it is easily accessible within every method of this class 00057 self.main = main 00058 00059 # We fill our frame (window) with the SystemPanel class, which shows the miniature of the visual window 00060 self.systemPanel = SystemPanel(self,self.main) 00061 00062 EVT_CLOSE(self,self.OnClose) 00063 00064 ## 00065 # We need to know when this window closes to update the view menu in the main window; 00066 # remove the hatch telling us whether this window is shown or not. 00067 # 00068 # Parameters: 00069 # @event - additional information sent from the close event trigger in this object 00070 # 00071 def OnClose(self,event): 00072 00073 self.main.ViewSystemsClick(False) 00074 00075 ## 00076 # Whenever something is changed in Visual Window, we need to redraw the contents of 00077 # the miniature window as well. This method is then called from the paint method in 00078 # Visual Window to inform this window that the miniature window needs a repaint. We 00079 # send the information further to the "real" miniature window: the system panel, 00080 # which actually shows the contents. 00081 # 00082 def DrawSystem(self): 00083 00084 self.systemPanel.DrawSystem(None,True) 00085 00086 ## 00087 # Whenever the status of the database connection changes, this needs to be informed 00088 # to "all" the classes, so it is this method that is called from its parent to tell 00089 # this. We need to tell the SystemPanel about this as well. At the moment we don't 00090 # need to take any action from this. 00091 # 00092 # Parameters: 00093 # @evtReason - A constant defining what kind of database connection change that occured. 00094 # @cdb - Reference to the database connection object. 00095 # 00096 def OnDbUpdate(self, evtReason, cdb): 00097 00098 self.systemPanel.OnDbUpdate(evtReason, cdb) 00099 00100 00101 ########################################################################## 00102 # SystemPanel class 00103 ########################################################################## 00104 00105 # Constants for SystemPanel 00106 CLOSE_BUTTON = 101 00107 CREATE_SUBSYSTEM = 8001 00108 CLOSE_WINDOW = 8002 00109 MODIFY_SUBSYSTEM = 8003 00110 SET_AS_ACTIVE = 8004 00111 00112 ## 00113 # This is the window in the SystemWindow that actually shows miniature versions of the 00114 # visual objects. 00115 # 00116 # Inherits wxPanel which is just a widget to contain other widgets... and implements of 00117 # course dbUpdate. 00118 # 00119 class SystemPanel(QWidget, dbUpdate): #wxPanel,dbUpdate): 00120 00121 00122 ## 00123 # Constructor. 00124 # 00125 # Parameters: 00126 # @parent - parent of this panel (usually SystemWindow) 00127 # @id - id of this window (for widget reference), set by the parent 00128 # @main - reference to the communication object (MainWindow) 00129 # 00130 # 00131 def __init__(self, main, parent): 00132 00133 #wxPanel.__init__(self,parent,id) 00134 QWidget.__init__(self,parent) 00135 self.main = main 00136 00137 # We use black as background colour for the miniature window; as in contrast to the 00138 # white background colour of the visual window. 00139 # self.SetBackgroundColour(wxColour(0,0,0)) 00140 00141 # We set the width and height of this window in member variables to use them when we 00142 # draw the miniature window. They are changed if the window is resized, so that it's 00143 # always correct relative positioning and size of the miniature object tot the real 00144 # visual objects 00145 self.width,self.height = self.GetSize() 00146 self.centerX = self.width/2 00147 self.centerY = self.height/2 00148 00149 # EVT_PAINT(self, self.DrawSystem) 00150 # EVT_SIZE(self,self.OnSize) 00151 00152 # EVT_LEFT_DOWN(self,self.OnMouseMove) 00153 # EVT_LEFT_UP(self,self.OnMouseMove) 00154 # EVT_MOTION(self,self.OnMouseMove) 00155 # EVT_LEAVE_WINDOW(self,self.OnLeftWindow) # Whenever the cursor leaves the window... 00156 00157 # Member variables needed to keep track of the red rectangle in our window; which 00158 # actually shows the shown part of the visual window. 00159 self.zoomarea = None # The rectangle object, size and position 00160 self.dragMode = -1 # Whether we drag (mousebutton down) or move (mousebutton up) while moving mouse cursor 00161 self.moveOriginX = -1 # Origin X of rectangle's last position 00162 self.moveOriginY = -1 # Origin Y of rectangle's last position 00163 self.movedX = -1 # Dragged X from rectangle's last position 00164 self.movedY = -1 # Dragged Y from rectangle's last position 00165 00166 ## 00167 # Whenever the status of the database connection changes, this needs to be informed 00168 # to "all" the classes, so it is this method that is called from its parent to tell 00169 # this. We clear the miniature window. (and hide it? TBC) 00170 # 00171 # Parameters: 00172 # @evtReason - A constant defining what kind of database connection change that occured. 00173 # @cdb - Reference to the database connection object. 00174 # 00175 def OnDbUpdate(self, evtReason, cdb): 00176 00177 if evtReason == DB_DISCONNECTED: 00178 self.DrawSystem(None,False) 00179 else: 00180 self.DrawSystem(None,True) #systems has to be redrawn each time the db is updated.. 00181 00182 ## 00183 # Whenever the cursor leaves the miniature window; we have to change it to the normal 00184 # cursor again; as we may have changed it to something else when dragging or resizing. 00185 # 00186 # Parameters: 00187 # @event - event object with information about the event 00188 # 00189 def OnLeftWindow(self,event): 00190 self.SetCursor(wxStockCursor(wxCURSOR_ARROW)) 00191 00192 ## 00193 # When the mouse cursor is moved around in this window (on the SystemPanel, which covers the 00194 # whole SystemWindow), we have to detect whether the we just move the mouse cursor or if we 00195 # also hold down the left mousebutton, and if it is the latter one, if the mouse cursor is 00196 # within the red rectangle. If all those are true: the user can move the red rectangle around, 00197 # and when he/she releases the mouse button the view in the visual window is changed. 00198 # 00199 # @event - event object; we make use of the x and y positions of the mouse cursor, and the 00200 # actions with the left mouse button (mouse down and mouse up) 00201 # 00202 def OnMouseMove(self,event): 00203 00204 setscrollbars = False # We do not change the view in the visual window as default, only if 00205 # the mouse button is released (mouse button up event) 00206 00207 # If the red rectangle object is not initialized yet, we ignore this call and return. 00208 if self.zoomarea == None: 00209 return False 00210 00211 # A left mouse button down event starts the dragging (if the mouse cursor is within the red rectangle area) 00212 if event.LeftDown(): 00213 mouse_x,mouse_y = event.GetX(),event.GetY() 00214 00215 # Check if the x and y position of the mouse cursor is inside the red rectangle's area 00216 if mouse_x >= self.zoomarea.GetPosition().x and mouse_x <= (self.zoomarea.GetPosition().x+self.zoomarea.GetSize().GetWidth()) and mouse_y >= self.zoomarea.GetPosition().y and mouse_y <= (self.zoomarea.GetPosition().y+self.zoomarea.GetSize().GetHeight()): 00217 self.dragMode = 1 # All right, it was inside the red rectangle; now we start dragging. 00218 00219 #Figure out where we clicked in the red rectangle, relatively to its upper left corner 00220 self.moveOriginX,self.moveOriginY = mouse_x,mouse_y 00221 00222 if event.Dragging(): # If we hold down the mouse button while we move the mouse cursor, we are dragging. 00223 # We then need to recalculate the new position of the red rectangle in the miniature 00224 # window as we drag 00225 if self.dragMode == 1: # Dragging started all right. 00226 mouse_x,mouse_y = event.GetX(),event.GetY() 00227 00228 rel_x = mouse_x - self.moveOriginX 00229 rel_y = mouse_y - self.moveOriginY 00230 00231 self.moveOriginX,self.moveOriginY = mouse_x,mouse_y 00232 self.zoomarea.SetRelativePosition(wxPoint(rel_x,rel_y)) 00233 00234 print "X: " + str(mouse_x) + " Y: " + str(mouse_y) 00235 00236 if event.LeftUp(): # We released the mouse button, thus dragging stopped (if any), and we then need to recalculate 00237 # the new position of the scroll bars in the visual window according to the new placement of the 00238 # red rectangle in the miniature window 00239 if self.dragMode == 1: 00240 self.dragMode = -1 00241 setscrollbars = True # Oh yeah, now we need to change the visual window view 00242 00243 if not (event.LeftDown() or event.Dragging() or event.LeftUp()): 00244 pass # None of the events that we were looking for occured...here we can optionally change the mouse cursor.. 00245 else: 00246 self.DrawSystem(None,False,setscrollbars) # Ok, a mouse event of our taste occured; action -> reaction 00247 # draw the new stuff. 00248 00249 ## 00250 # This is the paint method for this class disguised as a method to draw the system 00251 # in a miniature view. This method can be called from the system (paint event) or 00252 # an user (if we just need to repaint the window of some reason). 00253 # 00254 # Parameters: 00255 # @event - not used 00256 # @donotchangearea - (default: True), if we scroll on the scroll bars in the visual window, 00257 # then we would like to update the relative position of the red rectangle 00258 # to the rest of the SystemPanel as well. Only set when the scroll bars 00259 # change in the visual window by the user or by code. 00260 # @setScrollBars - (default: False), whether we should update the scroll bars of 00261 # the visual window or not (only on mouse button up after a drag 00262 # of the red rectangle) 00263 # 00264 def DrawSystem(self,event,donotchangearea=True,setScrollBars=False): 00265 00266 # We have to calculate the proportion between the size of the miniature window and the 00267 # visual window (the whole visual window with the hidden part included) so that we can 00268 # draw everything else in the correct proportions as well 00269 zoomwin_size = self.GetSize() # Size of the SystemPanel (miniature window) 00270 viswin_size = self.main.GetVisWindow().GetSize() # Size of the Visual Window, the visible part 00271 height_factor = float(zoomwin_size.GetHeight())/float(viswin_size.GetHeight()) 00272 width_factor = float(zoomwin_size.GetWidth())/float(viswin_size.GetWidth()) 00273 00274 viswin_maxwidth,viswin_maxheight = self.main.GetVisWindow().GetMaxSize() # Size of the Visual Window, the whole thing 00275 viswin_pos_x,viswin_pos_y = self.main.GetVisWindow().CalcUnscrolledPosition(0,0) # Get current scroll position 00276 00277 height_max_factor = float(zoomwin_size.GetHeight())/float(viswin_maxwidth) 00278 width_max_factor = float(zoomwin_size.GetWidth())/float(viswin_maxheight) 00279 00280 visobjects = self.main.GetVisWindow().GetContents() 00281 #selobjects = self.main.GetVisWindow().GetSelection() # If we want to draw the selected visual 00282 # objects with another colour etc, it's accessible 00283 00284 00285 if donotchangearea: 00286 if self.zoomarea == None: 00287 self.zoomarea = RectangleArea(wxPoint(viswin_pos_x*width_max_factor,viswin_pos_y*height_max_factor), wxSize(viswin_size.GetWidth()*width_max_factor,viswin_size.GetHeight()*height_max_factor)) 00288 else: 00289 self.zoomarea.SetPosition(wxPoint(viswin_pos_x*width_max_factor,viswin_pos_y*height_max_factor)) 00290 self.zoomarea.SetSize(wxSize(viswin_size.GetWidth()*width_max_factor,viswin_size.GetHeight()*height_max_factor)) 00291 00292 else: 00293 # Check if we tried to move the red rectangle out of the window, if so, set new position to edge of area 00294 if self.zoomarea.GetPosition().x + self.zoomarea.GetSize().GetWidth() > self.GetSize().GetWidth(): 00295 self.zoomarea.SetX(self.GetSize().GetWidth()-self.zoomarea.GetSize().GetWidth()) 00296 elif self.zoomarea.GetPosition().x < 0: 00297 self.zoomarea.SetX(0) 00298 if self.zoomarea.GetPosition().y + self.zoomarea.GetSize().GetHeight() > self.GetSize().GetHeight(): 00299 self.zoomarea.SetY(self.GetSize().GetHeight()-self.zoomarea.GetSize().GetHeight()) 00300 elif self.zoomarea.GetPosition().y < 0: 00301 self.zoomarea.SetY(0) 00302 00303 if setScrollBars: #set scrollbars in visual window to the area the user changed to in this window 00304 new_vis_x = self.zoomarea.GetPosition().x / width_max_factor 00305 new_vis_y = self.zoomarea.GetPosition().y / height_max_factor 00306 self.main.GetVisWindow().DoScroll(new_vis_x,new_vis_y) #upper left corner 00307 00308 if(event==None): 00309 dc = wxClientDC(self) # We explicitly requested an update 00310 else: 00311 dc = wxPaintDC(self) # The system thought that we would have need of an update 00312 00313 dc.BeginDrawing() 00314 dc.SetPen(wxBLACK_PEN) # Line colour 00315 dc.SetBrush(wxBLACK_BRUSH) # Fill colour 00316 00317 dc.DrawRectangle(0,0,zoomwin_size.GetWidth(),zoomwin_size.GetHeight()) # Whole area, covers whole SystemPanel 00318 00319 dc.SetPen(wxRED_PEN) 00320 00321 # Draw the red rectangle 00322 position = self.zoomarea.GetPosition() 00323 size = self.zoomarea.GetSize() 00324 dc.DrawRectangle(position.x,position.y,size.GetWidth(),size.GetHeight()) 00325 00326 # Draw miniature versions of objects (nodes/devices only) in visual window; in our miniature window 00327 for obj in visobjects: 00328 if obj.GetType() == obj_NODE: #only for nodes in device level (-1) 00329 dc.SetPen(wxPen(wxColour(255,255,0),width=1,style=wxSOLID)) # Yellow 00330 dc.SetBrush(wxBrush(wxColour(255,255,0),wxSOLID)) 00331 x,y = obj.GetPosition() 00332 w,h = obj.GetSize() 00333 00334 # If the miniature versions of our visual objects are to small, then we set a minimum size 00335 # of the miniature objects so that they are always visible for the user (if he/she is not blind) 00336 if w*width_max_factor < 1: 00337 w = 1 00338 else: 00339 w = w*width_max_factor 00340 if h*height_max_factor < 1: 00341 h = 1 00342 else: 00343 h = h*height_max_factor 00344 00345 dc.DrawRectangle(x*width_max_factor,y*height_max_factor, w, h) # Draw the node! 00346 00347 dc.EndDrawing() 00348 00349 ## 00350 # If we resize the miniature window, we redraw the contents with the new proportion 00351 # factor to the visual window. 00352 # 00353 def OnSize(self,event): 00354 00355 self.width,self.height = self.GetSize() 00356 self.centerX = self.width/2 00357 self.centerY = self.height/2 00358 00359 self.DrawSystem(None,donotchangearea=True,setScrollBars=False) # Needed because it is not intelligent enough to tell 00360 # that a resize needs a repaint...true enough. 00361 00362 ## 00363 # An object to store size and position of the red rectangle (which represents the visible visual window) 00364 # 00365 class RectangleArea: 00366 ## 00367 # Constructor. 00368 # Parameters: 00369 # @position - x and y position of the object in a wxPoint() object 00370 # @size - width and height of the object in a wxSize() object 00371 # 00372 def __init__(self,position,size): 00373 self.size = size 00374 self.position = position 00375 00376 ## 00377 # Get the size of the rectangle. 00378 # !returns a wxSize() object with width and height of the rectangle 00379 # 00380 def GetSize(self): 00381 return self.size 00382 00383 ## 00384 # Set the size of the rectangle. 00385 # Parameters: 00386 # @size - wxSize(w,h) object 00387 # 00388 def SetSize(self,size): 00389 self.size = size 00390 00391 ## 00392 # Get the position of the rectangle. 00393 # !returns a wxPoint() object width x and y position 00394 # 00395 def GetPosition(self): 00396 return self.position 00397 00398 ## 00399 # Set the absolute position of the rectangle. 00400 # Parameters: 00401 # @position - wxPoint(x,y) object 00402 # 00403 def SetPosition(self,position): 00404 self.position = position 00405 00406 ## 00407 # Set the relative position of the rectangle. 00408 # Parameters: 00409 # @position - wxPoint(x,y) object 00410 # 00411 def SetRelativePosition(self,position): 00412 self.position = wxPoint(self.position.x + position.x,self.position.y + position.y) 00413 00414 ## 00415 # Set the absolute x position of the rectangle. 00416 # Parameters: 00417 # @x - x position of the rectangle 00418 # 00419 def SetX(self,x): 00420 self.position = wxPoint(x,self.position.y) 00421 00422 ## 00423 # Set the absolute y position of the rectangle. 00424 # Parameters: 00425 # @y - y position of the rectangle 00426 # 00427 def SetY(self,y): 00428 self.position = wxPoint(self.position.x,y) 00429 00430 00431