2""" @brief Evolife Window system """
4#============================================================================#
5# EVOLIFE http://evolife.telecom-paris.fr Jean-Louis Dessalles
16if __name__ ==
'__main__': sys.path.append(
'../..')
18try:
from PyQt5
import QtGui, QtCore, QtWidgets
20 from PyQt4
import QtGui, QtCore
21 from PyQt4
import QtGui
as QtWidgets
34DefaultIconName =
'Graphics/EvolifeIcon.png'
35HelpFileName =
'Help.txt'
45 """ Controls the simulation, either step by step, or in
49 def __init__(self, SimulationStep, Obs, method='timer'):
50 """ Stores Obs as observer
51 and SimulationStep
as the function that processes one step of the simulation.
52 'method' can be
'timer' or 'thread' (
'timer' preferred)
66 """ Entering in 'Run' mode
74 """ Entering in 'Step' mode
83 """ Stops the simulation thread or timer
86 if self.
timer is not None and self.
timer.isActive():
88 elif self.
method ==
'thread':
99 """ (re)starts the simulation thread or timer
102 if self.
method ==
'timer':
104 if self.
timer is None:
105 self.
timer = QtCore.QTimer()
110 elif self.
method ==
'thread':
117 """ calls Simulation_launch
122 """ calls SimulationStep
130 traceback.print_exc()
164 """ Minimal control panel with [Run] [Step] [Help] and [quit] buttons
168 """ Creates a window with buttons that is also a Simulation_Control
170 self.Name = Obs.get_info('Title')
173 Simulation_Control.__init__(self, SimulationStep, Obs, method=
'timer')
174 Evolife_Graphic.Active_Frame.__init__(self, parent=
None, control=self)
176 self.setWindowTitle(self.
Name)
177 self.setWindowIcon(QtGui.QIcon(os.path.join(self.
Obs.get_info(
'EvolifeMainDir'), self.
IconName)))
193 NameLabel = QtWidgets.QLabel(
"<font style='color:blue;font-size:17px;font-family:Comic Sans MS;font-weight:bold;'>%s</font>" % self.
Name.upper(), self)
194 NameLabel.setAlignment(QtCore.Qt.AlignHCenter)
196 AdrLabel = QtWidgets.QLabel(
"<a href=http://www.dessalles.fr/%s>www.dessalles.fr/%s</a>" % (self.
Name.replace(
' ',
'_'), self.
Name), self)
197 AdrLabel.setAlignment(QtCore.Qt.AlignHCenter)
229 self.setGeometry(*Screen_.locate(200, 200, 140, 300))
233 def LocalButton(self, ParentFrame, ButtonType, Text, Tip, ClickFunction, ShortCutKey=None):
236 Button = ButtonType(Text, self)
237 Button.setToolTip(Tip)
238 Button.clicked.connect(ClickFunction)
239 if ShortCutKey
is not None:
240 Button.setShortcut(QtGui.QKeySequence(ShortCutKey))
241 ParentFrame.addWidget(Button)
245 """ opens Web browser with provided address
250 """ Displays a text file named: Help.txt
254 self.
SWindows[
'Help'].setWindowIcon(QtGui.QIcon(os.path.join(self.
Obs.get_info(
'EvolifeMainDir'),self.
IconName)))
256 self.
SWindows[
'Help'].
display(os.path.join(self.
Obs.get_info(
'EvolifeMainDir'), HelpFileName))
257 self.
SWindows[
'Help'].setGeometry(*Screen_.locate(400, 120, 600, 500))
260 self.
Obs.TextDisplay(
"Unable to find help file %s" % HelpFileName)
265 """ closes the window
272 """ puts the window in front of display
274 if self.isActiveWindow():
275 for SWName
in self.SWindows:
276 self.SWindows[SWName].raise_()
278 SWName = random.choice(list(self.SWindows.keys()))
279 self.SWindows[SWName].
Raise()
282 self.activateWindow()
286 """ close satelite windows and stops the simulation
289 self.simulation_steady_mode =
False
290 for (SWName,SW)
in list(self.SWindows.items()):
291 self.SWindows[SWName].close()
293 self.Simulation_stop()
297 """ A satellite window has been destroyed - removes it from the list
299 for SWName
in self.SWindows:
300 if self.SWindows[SWName] == SW:
301 del self.SWindows[SWName]
303 error(
'Evolife_Window',
'Unidentified destroyed window')
306 """ Processes graphic orders if in visible state
307 returns -1 if Observer says the simulation
is over
309 Simulation_Control.ReturnFromThread(self)
310 if self.Obs.Visible(): self.Process_graph_orders()
311 if self.Obs.Over():
return -1
315 """ Just let Observer know that display has taken place
318 self.CurrentFrame += 1
319 if self.PhotoMode == 1:
324 """ processes actions such as Run, Step, Help...
326 if e.key()
in [QtCore.Qt.Key_Q, QtCore.Qt.Key_Escape]:
328 elif e.key()
in [QtCore.Qt.Key_S, QtCore.Qt.Key_Space]:
329 self.StepButtonClick()
330 elif e.key()
in [QtCore.Qt.Key_R, QtCore.Qt.Key_C]:
331 self.Buttons[
'Run'].animateClick()
332 elif e.key()
in [QtCore.Qt.Key_H, QtCore.Qt.Key_F1]:
333 self.Buttons[
'Help'].animateClick()
334 elif e.key()
in [QtCore.Qt.Key_M]:
337 try: self.Obs.inform(str(e.text()))
338 except UnicodeEncodeError:
pass
341 """ Sends event to observer (useful for mouse events)
344 self.Obs.recordInfo(Event.EventType, (Event.EmittingClass, Event.Info))
351 """ This class combines a control panel and a slider for controlling display period
354 def __init__(self, SimulationStep, Obs, Background=None):
355 """ Create Control frame + displayperiod slider
358 Simulation_Control_Frame.__init__(self, SimulationStep, Obs)
361 self.
lcd = QtWidgets.QLCDNumber(self)
362 self.
lcd.SegmentStyle(QtWidgets.QLCDNumber.Filled)
363 lcdPalette = QtGui.QPalette()
364 lcdPalette.setColor(QtGui.QPalette.Light, QtGui.QColor(200,10,10))
365 self.
lcd.setPalette(lcdPalette)
376 """ The displayed value varies exponentially with the slider's position
379 if (disp > 2999): disp = ((disp+500) // 1000) * 1000
380 elif (disp > 299): disp = ((disp+50) // 100) * 100
381 elif (disp > 29): disp = ((disp+5) // 10) * 10
382 elif (disp > 14): disp = ((disp+2) // 5) * 5
390 if Period == 0: Period = 1
402 """ This class combines a control panel and a space to display curves
405 def __init__(self, SimulationStep, Obs, Background=None):
406 """ Creates a plot area and displays it to the right of the control frame
409 Simulation_Display_Control_Frame.__init__(self, SimulationStep, Obs)
410 self.setGeometry(*Screen_.locate(50, 50, 702, 420))
426 """ Displays a text file named:
430 self.
SWindows[
'Legend'].setWindowIcon(QtGui.QIcon(os.path.join(self.
Obs.get_info(
'EvolifeMainDir'),self.
IconName)))
432 self.
plot_area.Area.Curvenames(self.
Obs.get_info(
'CurveNames'))
433 Comments = self.
Obs.get_info(
'WindowLegends')
436 self.
SWindows[
'Legend'].setGeometry(*Screen_.locate(50, 550, 600, 150))
439 self.
Obs.TextDisplay(
"Unable to find information on curves")
447 """ Processes graph orders received from observer.
448 Displays PlotData by adding points to curves and by displaying them.
454 self.
Obs.TextDisplay(
'%s Created' % ImgC)
456 PlotData = self.
Obs.get_info(
'PlotOrders')
458 for (CurveId, Point)
in PlotData:
459 self.
plot_area.Area.plot(CurveId, Point, Width=3*Screen_.ratio)
460 Simulation_Control_Frame.Process_graph_orders(self)
463 """ store and print simulation results
466 RF = self.
Obs.get_info(
'ResultFile')
468 self.
plot_area.Area.Curvenames(self.
Obs.get_info(
'CurveNames'))
469 AverageValues = self.
plot_area.Area.dump(RF, self.
Obs.get_info(
'ResultHeader'),
470 self.
Obs.get_info(
'ResultOffset', 0))
472 self.
Obs.TextDisplay(
'\n. ' +
'\n. '.join([
'%s\t%s' % (C, AverageValues[C])
for C
in sorted(AverageValues)]))
473 self.
Obs.TextDisplay(
'\nResults stored in %s*.csv' % os.path.normpath(RF))
476 """ close parent closeEvent
480 Simulation_Control_Frame.closeEvent(self, event)
488 """ Defines Evolife main window by modification of the generic Simulation Frame
491 def __init__(self, SimulationStep, Obs, Capabilities='C', Options=[]):
492 """ Creation of the main window and active satelite windows
505 if Obs.get_info(
'Background')
is not None:
506 self.
Background[
'Default'] = Obs.get_info(
'Background')
507 for W
in [
'Curves',
'Genomes',
'Photo',
'Trajectories',
'Network',
'Field',
'Log',
'Image']:
508 self.
Background[W] = Obs.get_info(W +
'Wallpaper')
516 Simulation_Frame.__init__(self, SimulationStep, Obs, Background=self.
Background[
'Curves'])
517 elif set(
'FRGNT') & set(Capabilities):
518 self.
ParentClass = Simulation_Display_Control_Frame
519 Simulation_Display_Control_Frame.__init__(self, SimulationStep, Obs)
522 Simulation_Control_Frame.__init__(self, SimulationStep, Obs)
549 DefViews = self.
Obs.get_info(
'DefaultViews')
554 if type(B) == str: self.
Buttons[B].animateClick()
555 elif type(B) == tuple:
556 self.
Buttons[B[0]].animateClick()
564 elif DefViews
is None:
565 for B
in [
'Trajectories',
'Field',
'Network',
'Genomes',
'Log']:
572 self.
Buttons[
'Run'].animateClick()
576 """ recognizes shortcuts to show satelite windows (Genomes, Trajectories, Field, Legend, Film...)
581 if e.key() == QtCore.Qt.Key_G: self.
Buttons[
'Genomes'].animateClick()
582 if e.key() == QtCore.Qt.Key_P: self.
Buttons[
'Photo'].animateClick()
583 if e.key() == QtCore.Qt.Key_T: self.
Buttons[
'Trajectories'].animateClick()
584 if e.key() == QtCore.Qt.Key_N: self.
Buttons[
'Network'].animateClick()
585 if e.key() == QtCore.Qt.Key_F: self.
Buttons[
'Field'].animateClick()
586 if e.key() == QtCore.Qt.Key_L: self.
Buttons[
'Log'].animateClick()
587 if e.key() == QtCore.Qt.Key_I: self.
Buttons[
'Image'].animateClick()
588 if e.key() == QtCore.Qt.Key_D: self.
Buttons[
'Legend'].animateClick()
590 except KeyError:
pass
594 if 'Genomes' not in self.
Buttons:
return
597 outputDir=self.
Obs.get_info(
'OutputDir'),
598 image=self.
Background[
'Genomes'], zoom=Screen_.ratio)
600 self.
SWindows[
'Genomes'].move(*Screen_.locate(800, 200))
605 """ saves a snapshot of the simulation and goes to stepwise mode
607 if 'Photo' not in self.
Buttons:
return
609 self.
Obs.TextDisplay(
'Photo mode ended\n')
614 self.
Obs.TextDisplay(
'\nPhoto mode' + self.
Obs.__str__() +
'\n' +
'Frame %d' % self.
CurrentFrame)
618 """ Film mode is activated by pressing the 'V' key (video)
619 It results in images (snapshots) being saved each time Observer
is 'visible'
621 if 'Photo' not in self.
Buttons:
return
625 self.setWindowTitle(
"%s (FILM MODE)" % self.
Name)
626 else: self.setWindowTitle(self.
Name)
629 """ displays the 'Trajectories' window
631 if 'Trajectories' not in self.
Buttons:
return
632 if 'Trajectories' not in self.
SWindows:
634 Wtitle=
'Trajectories',
635 outputDir=self.
Obs.get_info(
'OutputDir'),
636 image=self.
Background[
'Trajectories'], zoom=Screen_.ratio)
638 self.
SWindows[
'Trajectories'].move(*Screen_.locate(275, 500))
643 """ displays the 'Network' window
645 if 'Network' not in self.
Buttons:
return
648 outputDir=self.
Obs.get_info(
'OutputDir'),
649 image=self.
Background[
'Network'], zoom=Screen_.ratio)
651 self.
SWindows[
'Network'].move(*Screen_.locate(790, 500))
655 """ displays the 'Field' window
657 if 'Field' not in self.
Buttons:
return
661 outputDir=self.
Obs.get_info(
'OutputDir'),
662 image=self.
Background[
'Field'], zoom=Screen_.ratio)
664 self.
SWindows[
'Field'].move(*Screen_.locate(800, 100))
669 """ [not implemented]
671 if 'Log' not in self.
Buttons:
return
672 self.
Obs.TextDisplay(
'LogTerminal\n')
676 """ Sets Satellite window's geometry, icon and title
678 self.SWindows[WindowName].setWindowIcon(QtGui.QIcon(os.path.join(self.Obs.get_info('EvolifeMainDir'),self.
IconName)))
687 """ sets the availability of the 'Network', 'Field', 'Image', 'Trajectories' tick button on display
690 if B
in [
'Network',
'Field',
'Image',
'Trajectories',
'Log']:
692 self.
Buttons[B].setCheckState(
False)
694 self.
Buttons[B].setCheckState(
True)
697 """ Processes graph orders received from observer.
698 Parent class displays PlotData by adding points to curves and by displaying them.
699 In addition, gets orders
for satelite windows
from Oberver
and processes them.
702 ImgG, ImgN, ImgF, ImgT = ('',) * 4
704 ImgG = self.
SWindows[
'Genomes'].genome_display(genome=self.
Obs.get_data(
'DNA'),
705 gene_pattern=self.
Obs.get_info(
'GenePattern'),
708 ImgN = self.
SWindows[
'Network'].Network_display(self.
Obs.get_data(
'Field', Consumption=
False),
709 self.
Obs.get_data(
'Network'),
712 self.
SWindows[
'Field'].image_display(self.
Obs.get_info(
'Image'), windowResize=
True)
713 ImgF = self.
SWindows[
'Field'].Field_display(self.
Obs.get_data(
'Field'),
718 self.
SWindows[
'Trajectories'].image_display(self.
Obs.get_info(
'Pattern'), windowResize=
True)
719 ImgT = self.
SWindows[
'Trajectories'].Field_display(self.
Obs.get_data(
'Trajectories'),
723 if ''.join([ImgG, ImgN, ImgF, ImgT]):
724 self.
Obs.TextDisplay(
'%s Created' %
' '.join([ImgG, ImgN, ImgF, ImgT]))
729 """ Exits if 'ExitOnEnd' is True
731 if 'ExitOnEnd' in self.
DOptions and self.
DOptions[
'ExitOnEnd']
in [
True,
'Yes']:
734 self.
Buttons[
'Quit'].animateClick()
749def Start(SimulationStep, Obs, Capabilities='C', Options={}):
750 """ SimulationStep is a function that performs a simulation step
751 Obs is the observer that stores statistics
752 Capabilities (curves, genome display, trajectory display...)
753 = any string of letters
from: CFGNTP
755 F = Field (2D seasonal display) (excludes R)
757 I = Image (same
as Field, but no slider)
759 N = social network display
760 P = Photo (screenshot)
761 R = Region (2D ongoing display) (excludes F)
762 T = Trajectory display
765 - Run:
True means that the simulation will run automatically
766 - Background:<Colour
or image>
767 - ExitOnEnd:
True doesn
't pause when simulation stops
771 MainApp = QtWidgets.QApplication(sys.argv)
774 Screen_ = Screen.Screen_(MainApp) # stores physical dimensions of display
775 Screen_.switchScreen()
777 if set(Capabilities) <= set('CFGILNPRT'):
779 MainWindow =
Evolife_Frame(SimulationStep, Obs, Capabilities, Options)
784 MainApp.deleteLater()
787 print(
""" Error: <Capabilities> should be a string of letters taken from:
789 F = Field (2D seasonal display) (excludes R)
791 I = Image (same
as Field, but no slider)
793 N = social network display
794 P = Photo (screenshot)
795 R = Region (2D ongoing display) (excludes F)
796 T = Trajectory display
802if __name__ ==
'__main__':
807__author__ =
'Dessalles'
An Active_frame reacts to basic keyboard control.
def Raise(self)
puts the window on top of display
Standard canvas plus resizing capabilities.
def photo(self, Name, FrameNumber=-1, outputDir='.', extension='png')
takes a snapshot and saves it to a new file
A graphic area that displays moving agents #.
Genome_window: An image area that displays binary genomes.
Displays a text file supposed to provide help.
displays legend for curves
Network_window: A drawing area that displays social links The population is displayed twice,...
Synonymous for Field_window.
Defines Evolife main window by modification of the generic Simulation Frame.
FieldOngoingDisplay
Control panel #.
def __init__(self, SimulationStep, Obs, Capabilities='C', Options=[])
Creation of the main window and active satelite windows.
def TrajectoryButtonClick(self, event)
displays the 'Trajectories' window
def NetworkButtonClick(self, event)
displays the 'Network' window
def PhotoButtonClick(self, event)
saves a snapshot of the simulation and goes to stepwise mode
def FieldButtonClick(self, event)
displays the 'Field' window
def WindowActivation(self, WindowName)
Sets Satellite window's geometry, icon and title.
def SWDestroyed(self, SW)
def keyPressEvent(self, e)
recognizes shortcuts to show satelite windows (Genomes, Trajectories, Field, Legend,...
def DecisionToEnd(self)
Exits if 'ExitOnEnd' is True.
def GenomeButtonClick(self, event)
def FilmButtonClick(self, event)
Film mode is activated by pressing the 'V' key (video) It results in images (snapshots) being saved e...
def LogButtonClick(self, event)
[not implemented]
def Process_graph_orders(self)
Processes graph orders received from observer.
def checkButtonState(self)
sets the availability of the 'Network', 'Field', 'Image', 'Trajectories' tick button on display
Capabilities
Creation of the main window #.
def closeEvent(self, event)
close parent closeEvent
Minimal control panel with [Run] [Step] [Help] and [quit] buttons.
def QuitButtonClick(self, event)
closes the window
def __init__(self, SimulationStep, Obs)
Creates a window with buttons that is also a Simulation_Control.
def LocalButton(self, ParentFrame, ButtonType, Text, Tip, ClickFunction, ShortCutKey=None)
Creates a button.
def HelpButtonClick(self, event=None)
Displays a text file named: Help.txt.
SWindowsPreferredGeometry
def EvolifeWebSite(self, e)
opens Web browser with provided address
SWindows
List and status of Satellite windows.
Interface with the simulation thread #.
def OneStep(self)
calls SimulationStep
def Simulation_resume(self)
calls Simulation_launch
def StepButtonClick(self, event=None)
Entering in 'Step' mode.
def RunButtonClick(self, event=None)
Entering in 'Run' mode.
simulation
Status of the simulation programme.
def Simulation_launch(self, continuous_mode)
(re)starts the simulation thread or timer
def DecisionToEnd(self)
to be overloaded
def ReturnFromThread(self)
to be overloaded
def Simulation_stop(self)
Stops the simulation thread or timer.
This class combines a control panel and a slider for controlling display period.
def DisplayPeriodSet(self, Period, FlagForce=True)
def __init__(self, SimulationStep, Obs, Background=None)
Create Control frame + displayperiod slider.
def DisplayPeriodChanged(self, event)
The displayed value varies exponentially with the slider's position.
This class combines a control panel and a space to display curves.
def dump(self, verbose=False)
store and print simulation results
def __init__(self, SimulationStep, Obs, Background=None)
Creates a plot area and displays it to the right of the control frame.
def LegendButtonClick(self, event=None)
Displays a text file named:
def closeEvent(self, event)
close parent closeEvent
def Process_graph_orders(self)
Processes graph orders received from observer.
Graphic area for displaying curves #.
def display(self)
calling 'display' for all individuals in the population
def Start(SimulationStep, Obs, Capabilities='C', Options={})
SimulationStep is a function that performs a simulation step Obs is the observer that stores statisti...
def closeEvent(self, event)
close satelite windows and stops the simulation
def keyPressEvent(self, e)
processes actions such as Run, Step, Help...
def ReturnFromThread(self)
Processes graphic orders if in visible state returns -1 if Observer says the simulation is over.
def Raise(self)
if self.closeEvent(None): QtCore.QCoreApplication.instance().quit()
def SWDestroyed(self, SW)
A satellite window has been destroyed - removes it from the list.
def EventInterpreter(self, Event)
Sends event to observer (useful for mouse events)
def Process_graph_orders(self)
Just let Observer know that display has taken place.