Explorar el Código

Changes mainly for the GUI.

RuneOptimizer:
 - Compiler optimization, way faster now
 - Fixed GUI output for optimize and update commands.

RuneOptimizerGUI:
 - Calls to the CLI are now async and don't block the UI. Added progress indicator and messages.
 - Beter current set detection in the optimizer view.
 - Button to go to the optimizer from the unit view.
 - Redirect to results once the optimization is complete.
 - Code clean up.
Iñigo Valentin hace 4 años
padre
commit
ac5d1ca4b1

+ 1 - 1
src/Makefile

@@ -1,7 +1,7 @@
 CC=gcc
 CFLAGS=
 OPTS_DEBUG=-Wall -g -fsanitize=address
-OPTS=
+OPTS=-O3
 LIBS=-lsqlite3 -lm -ljson-c
 OUT=../RuneOptimizer
 compile :

+ 23 - 11
src/RuneOptimizer/optimize/optimize.c

@@ -1340,10 +1340,10 @@ int gui_output(Result results[5000], int result_count){
     char tmp[300];
     strcpy(tmp, "");
     char json[300];
-    printf("{\"result_count\":%d,\"results\":[\n", result_count);
+    printf("{\"result_count\":%d,\"results\":[", result_count);
     int result_limit = 100;
     for (int i = 0; i < result_count && i < result_limit; i++){
-        //printf("RES LOOP %d\n", i);
+        //printf("RES LOOP %d", i);
         sprintf(tmp, "{\"id\":%d,\"rating\":%d,", i, results[i].rating);
         strcpy(json, tmp);
         sprintf(tmp, "\"hp\":%d,", results[i].stats.hp);
@@ -1368,13 +1368,13 @@ int gui_output(Result results[5000], int result_count){
         sprintf(tmp, "\"dmg\":%d,", results[i].stats.dmg);
         strcat(json, tmp);
         strcat(json, "\"runes\":[");
-        //printf("    A %s\n", json);
+        //printf("    A %s", json);
         for (int j = 0; j < 5; j++){
-            //printf("    RUNE LOOP %d\n", j);
+            //printf("    RUNE LOOP %d", j);
             sprintf(tmp, "\"%s\",", results[i].rune_ids[j]);
             strcat(json, tmp);
         }
-        //printf("    B %s\n", json);
+        //printf("    B %s", json);
         sprintf(tmp, "\"%s\"", results[i].rune_ids[5]);
         strcat(json, tmp);
         strcat(json, "]},");
@@ -1385,7 +1385,7 @@ int gui_output(Result results[5000], int result_count){
         }
 
         printf(json);
-        printf("\n");
+        printf("");
     }
     // Remove last comma
     //json[strlen(json) - 1] = '\0';
@@ -1393,10 +1393,10 @@ int gui_output(Result results[5000], int result_count){
 
     // End and print
     printf("]}\n");
-    //printf("STRLEN JSON %d\n", strlen(json));
+    //printf("STRLEN JSON %d", strlen(json));
     //printf("%s", json);
     //free(*json);
-    //printf("\n\nEND\n\n");
+    //printf("END");
     return SUCCESS;
 }
 
@@ -1531,6 +1531,10 @@ int optimize(int argc, char *argv[]){
     if (gui != 1){
         printf("\n\n__Optimization progress___________________________\n");
     }
+    else{
+        printf("Total combinations: %d\n", max_combinations);
+        fflush(stdout);
+    }
 
     // Initialize arrys and some counters
     int index[7] = {0, 0, 0, 0, 0, 0};
@@ -1550,12 +1554,20 @@ int optimize(int argc, char *argv[]){
     ){
         // Progress bar, 50 characters to 100%
         if (
-          gui != 1 &&
           (tested_combinations + 1) %
           (unsigned long)(max_combinations / 50)
           == 0
         ){
-            printf("#");
+            if (gui != 1){
+                printf("#");
+            }
+            else{
+                // For GUI flushing, newlines are required
+                printf(
+                  "%d\n",
+                  (unsigned long)( (tested_combinations + 1) /
+                  (unsigned long)(max_combinations / 20)));
+            }
             // Line buffered! need to flush after every char.
             fflush(stdout);
         }
@@ -1864,7 +1876,7 @@ int optimize(int argc, char *argv[]){
             printf("No results found\n");
         }
         else{
-            fprintf(stderr, "No results found\n");
+            printf("{\"result_count\":0,\"results\":[]}\n");
         }
     }
     return SUCCESS;

+ 141 - 40
src/RuneOptimizerGUI/classes/DialogUpdateJson.py

@@ -22,20 +22,58 @@ class DialogUpdateJson(wx.Dialog):
 
     Parameters
     ----------
+    formSizer : wx.BoxSizer
+        Sizer with the file selector and options.
+    progressSizer : wx.BoxSizer
+        Sizer with the progress image. Hidden on class creation.
+    messageSizer : wx.BoxSizer
+        Sizer with the progress message box. Hidden on class creation.
+    buttonSizer : wx.BoxSizer
+        Contains the accept button.
     fileSelector : wxFilePickerCtrl.
         File selector
-    unitsStars : wx.Checkbox.
+    starsCheck : wx.Checkbox.
         Checkbox to indicate to save only units with 6 stars.
-    unitsStars : wx.Checkbox.
+    runesCheck : wx.Checkbox.
         Checkbox to indicate to save only units with runes.
-    clearTeams : wx.Checkbox.
+    teamsCheck : wx.Checkbox.
         Checkbox to indicate team deletion.
+    updateDone : boolean
+        Indicates if the update process has been run (default False)
+    updateError : boolean
+        Indicates if the update process has been run with errors (default False)
+    messageLabel : wx.StaticText
+        Label wich shows the output of the update process.
+    timer : wx.Timer
+        Timer to check the update process for new output to display.
+    process : wx.Process
+        The update process.
+
+    Methods
+    -------
+    checkProcess(event)
+        Checks the update process for new output.
+    updateComplete(event)
+        Called at process end, cleans the dialog and set status variables.
+    accept(event)
+        Checks from accept button. Starts the update process.
 
     """
 
+    formSizer = None
+    progressSizer = None
+    messageSizer = None
+    buttonSizer = None
     fileSelector = None
+    starsCheck = None
+    runesCheck = None
+    teamsCheck = None
     updateDone = False
     updateError = False
+    messageLabel = None
+    timer = None
+    process = None
+    process = None
 
     def __init__(self, parent, id=wx.ID_ANY):
         """Initializes the panel.
@@ -49,37 +87,37 @@ class DialogUpdateJson(wx.Dialog):
           self, parent=parent, id=id, pos=(50, 50), size=(400, 290)
         )
 
-        self.form = wx.BoxSizer(wx.VERTICAL)
-        self.progress = wx.BoxSizer(wx.VERTICAL)
-        self.messages = wx.BoxSizer(wx.VERTICAL)
+        self.formSizer = wx.BoxSizer(wx.VERTICAL)
+        self.progressSizer = wx.BoxSizer(wx.VERTICAL)
+        self.messageSizer = wx.BoxSizer(wx.VERTICAL)
         self.buttonSizer = wx.BoxSizer(wx.VERTICAL)
 
         fileSelectorLabel = wx.StaticText(
             parent=self,  id=wx.ID_ANY, label="Select a JSON file",
             pos=(30, 30), size=(130, 30)
           )
-        self.form.Add(fileSelectorLabel)
+        self.formSizer.Add(fileSelectorLabel)
         self.fileSelector = wx.FilePickerCtrl(parent=self,
           id=wx.ID_ANY, path="",
           message="Select JSON file", wildcard="JSON files (*.json)|*.json",
           style=wx.FC_DEFAULT_STYLE, pos=(140, 20), size=(250, 40)
         )
-        self.form.Add(self.fileSelector)
-        self.unitsStars = wx.CheckBox(
+        self.formSizer.Add(self.fileSelector)
+        self.starsCheck = wx.CheckBox(
           parent=self, id=wx.ID_ANY, label="Only import units at with 6 stars.",
           pos=(30, 80), size=(230, 20)
         )
-        self.form.Add(self.unitsStars)
-        self.unitsRunes = wx.CheckBox(
+        self.formSizer.Add(self.starsCheck)
+        self.runesCheck = wx.CheckBox(
           parent=self, id=wx.ID_ANY, label="Only import units with runes.",
           pos=(30, 110), size=(230, 20)
         )
-        self.form.Add(self.unitsRunes)
+        self.formSizer.Add(self.runesCheck)
         self.clearTeams = wx.CheckBox(
           parent=self, id=wx.ID_ANY, label="Clear team data",
           pos=(30, 140), size=(230, 20)
         )
-        self.form.Add(self.clearTeams)
+        self.formSizer.Add(self.clearTeams)
 
         self.btAccept = wx.Button(
           parent=self, id=wx.ID_ANY, pos=(100, 180),
@@ -92,22 +130,96 @@ class DialogUpdateJson(wx.Dialog):
         self.buttonSizer.Add(self.btAccept)
         self.Bind(wx.EVT_BUTTON, self.accept, self.btAccept)
 
+        anim = wx.adv.Animation(
+          os.path.dirname(os.path.realpath(__file__)) + '/res/icon/progress.gif'
+        )
+        progressCtrl = wx.adv.AnimationCtrl(
+          parent=self, id=wx.ID_ANY, anim=anim, pos=(126, 176), size=(48, 48)
+        )
+        progressCtrl.Play()
+        self.progressSizer.Add(progressCtrl)
+
         # Progress message
-        self.message = wx.StaticText(
+        self.messageLabel = wx.StaticText(
           parent=self,  id=wx.ID_ANY, label="",
           pos=(20, 20), size=(340, 460)
         )
-        self.messages.Add(self.message)
+        self.messageSizer.Add(self.messageLabel)
+
+        # Hide progress bar and messages
+        self.progressSizer.ShowItems(False)
+        self.messageSizer.ShowItems(False)
+
+    def checkProcess(self, event):
+        """Checks the process output and updates the progress message.
+
+        Parameters
+        ----------
+        event : wxEvent, optional
+            The event that triggered the call.
+
+        """
+
+        if self.process is not None:
+            stream = self.process.GetInputStream()
+            if stream.CanRead():
+                text = bytes.decode(stream.read())
+                #text = text[:-1] # Remove the last newline
+                self.messageLabel.SetLabel(text)
+        else:
+            self.timer.Stop()
+
+    def updateComplete(self, event):
+        """Called when the update process is complete.
+
+        Hiddes the progress image, checks for errors in the output, prints a
+        message annd sets self.updateDone and self.updateError.
+
+        Parameters
+        ----------
+        event : wxEvent, optional
+            The event that triggered the call.
+
+        """
+
+        self.timer.Stop()
+        self.progressSizer.ShowItems(False)
+        errStream = bytes.decode(self.process.GetErrorStream().read())
+        if errStream == "":
+            self.messageLabel.SetLabel(
+              self.messageLabel.GetLabel() + "\nAll done!"
+            )
+            self.updateDone = True
+            self.updateError = False
+        else:
+            self.messageLabel.SetLabel(
+              self.messageLabel.GetLabel() +
+              "\nUpdate didnt' complete succesfully"
+            )
+            self.updateDone = True
+            self.updateError = True
 
     def accept(self, event):
-        self.form.ShowItems(False)
+        """Called when the accept button is clicked.
+
+        Hiddes the form and shows the progress image and message box, composes
+        the command and launchs it
+
+        Parameters
+        ----------
+        event : wxEvent, optional
+            The event that triggered the call.
+
+        """
+        self.formSizer.ShowItems(False)
+        self.progressSizer.ShowItems(True)
+        self.messageSizer.ShowItems(True)
         self.buttonSizer.ShowItems(False)
-        self.Update()
         command = "RuneOptimizer update "
         command += pipes.quote(self.fileSelector.GetPath())
-        if self.unitsStars.GetValue():
+        if self.starsCheck.GetValue():
             command += " --six-stars"
-        if self.unitsRunes.GetValue():
+        if self.runesCheck.GetValue():
             command += " --with-runes"
         if self.clearTeams.GetValue():
             command += " --clear-teams"
@@ -115,25 +227,14 @@ class DialogUpdateJson(wx.Dialog):
         command = \
           os.path.dirname(os.path.realpath(__file__)) + "/../../" + command
         print("Command: " + command)
-        process = \
-          subprocess.Popen(command.split(),shell=False,stdout=subprocess.PIPE)
-
-        # Poll process.stdout to show stdout live
-        while True:
-            output = process.stdout.readline()
-            if process.poll() is not None:
-                break
-            if output:
-                self.message.SetLabel(self.message.GetLabel() + bytes.decode(output.strip()) + "\n")
-            self.Update()
-        self.Update()
-        rc = process.poll()
-
-        if process.returncode == 0:
-            self.message.SetLabel(self.message.GetLabel() + "\nAll done!")
-            self.updateDone = True
-            self.updateError = False
-        else:
-            self.updateDone = True
-            self.updateError = True
 
+        # Timer ot periodically check on the process
+        self.timer = wx.Timer(self)
+        self.timer.Start(1000)
+        self.Bind(wx.EVT_TIMER, self.checkProcess)
+
+        # Create the process
+        self.Bind(wx.EVT_END_PROCESS, self.updateComplete)
+        self.process = wx.Process(self)
+        self.process.Redirect()
+        wx.Execute(command, wx.EXEC_ASYNC, self.process)

+ 321 - 155
src/RuneOptimizerGUI/classes/PanelOptimizer.py

@@ -24,49 +24,62 @@ class PanelOptimizer(wx.Panel):
     ----------
     unitId : string
         Currently selected unit ID (default None)
-    optimizationOptions : wx.BoxSizer
-        Holds every widget that is hidden until a unit is selected.
-    unitInfo : wx.StaticBox
-        Box containig the non-editable elements with a unit info.
+    unitStats : int[10]
+        The current stats of the selected unit (HP, ATK, DEF, SPD, CRR, CRD,
+        RES, ACC). (default is [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).
+    teamIds : string[]
+        IDs of all teams, indexed by the order they appear in the team selector.
     unitIdSelectorIndex : int[]
         Array with the IDs of all units, in the same order as displayed in
-        unitSelector, so an ID can be retrived knowing the choice
+        unitChoice, so an ID can be retrived knowing the choice
         selected index.
-    unitSelector : wx.Choice
+    optionsSizer : wx.BoxSizer
+        Holds every widget that is hidden until a unit is selected.
+    unitInfoBox : wx.StaticBox
+        Box containig the non-editable elements with a unit info.
+    unitChoice : wx.Choice
         Unit selecctor. Choosing a unit triggers selectUnit.
     statGrid : wx.Grid.grid
         Table with the unit base and current stats.
-    runeList : wx.StaticText[6]
+    runeLabelList : wx.StaticText[6]
         Labels with all the info about the currently equipped runes.
-    minStatSlid : wx.Slider[6]
+    minStatSlidList : wx.Slider[6]
         List of sliders for the minimum selectors for each stat.
-    minStatText : wx.StaticText[6]
+    minStatTextList : wx.StaticText[6]
         List of text inputs for the minimum selectors for each stat.
-    stats : wx.CheckListBox[2]
+    statCheckListList : wx.CheckListBox[2]
         Tho selctors to choose stats allowed in optimization.
-    runeSets : wx.Choice[3]
+    setChoiceList : wx.Choice[3]
         List of selector to pik rune sets.
-    level : wx.Choice
+    levelChoice : wx.Choice
         Selector to pick the level for the rune optimization.
-    inventory : wx.Checkbox
+    inventoryCheck : wx.Checkbox
         Checkbox to use only runes in the inventory
-    teams : wx.CheckboxList :
+    teamCheckList : wx.CheckboxList :
         List of selectable teams to exclude from the optimization.
-    unitStats : int[10]
-        The current stats of the selected unit. (default is
-        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).
-    teamIds : string[]
-        IDs of all teams, indexed by the order they appear in the team selector.
+    progressGauge : wx.Gauge
+        A progress bar
+    timer : wx.Timer
+        Timer to check the update process for new output to display.
+    process : wx.Process
+        The update process.
 
     Methods
     -------
+    selectAllTeams(event)
+        Selects all teams in the list.
+    deselectAllTeams(event)
+        Deselects all teams in the list.
     selectUnit(event)
         Loads a unit info and enables optimizaton options.
     processResults(jsonData)
         Processes data obtained from RuneOptimizer.
-
     startOptimization(event)
         Prepares and runs a command optimization.
+    checkProcess(event)
+        Checks the process and update the progress bar.
+    updateComplete(event)
+        Called at process end, rediresct to the result view.
     minStatChangeBySlider(event)
         Changes text when a slider is changed.
     minStatChangeByTExt(event)
@@ -75,21 +88,24 @@ class PanelOptimizer(wx.Panel):
     """
 
     unitId = None
-    optimizationOptions = None
-    unitInfo = None
-    unidIdSelectorIndex = []
-    unitSelector = None
-    statGrid = None
-    runeList = None
-    minStatSlid = None
-    minStatText = None
-    stats = None
-    runeSets = None
-    level = None
-    inventory = None
-    teams = None
     unitStats = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
     teamIds = []
+    unidIdSelectorIndex = []
+    optionsSizer = None
+    unitInfoBox = None
+    unitChoice = None
+    statGrid = None
+    runeLabelList = None
+    minStatSlidList = None
+    minStatTextList = None
+    statCheckListList = None
+    setChoiceList = None
+    levelChoice = None
+    inventoryCheck = None
+    teamCheckList = None
+    progressGauge = None
+    timer = None
+    process = None
 
     def __init__(self, parent, id=wx.ID_ANY):
         """Initializes the panel.
@@ -109,10 +125,10 @@ class PanelOptimizer(wx.Panel):
 
         # Sizer for all optimization options. Will be hidden until a unit is
         # selected.
-        self.optimizationOptions = wx.BoxSizer(wx.VERTICAL)
+        self.optionsSizer = wx.BoxSizer(wx.VERTICAL)
 
         # Unit info box
-        self.unitInfo = wx.StaticBox(
+        self.unitInfoBox = wx.StaticBox(
           self, label="Select unit:", id=wx.ID_ANY, pos=(10, 0), size=(450, 300)
         )
 
@@ -122,15 +138,15 @@ class PanelOptimizer(wx.Panel):
         for row in cursor:
             names.append(row[1])
             self.unidIdSelectorIndex.append(row[0])
-        self.unitSelector =wx.Choice(
-          parent=self.unitInfo, id=wx.ID_ANY, pos=(10, 0),
+        self.unitChoice =wx.Choice(
+          parent=self.unitInfoBox, id=wx.ID_ANY, pos=(10, 0),
           size=(200, 30), choices=names
         )
-        self.Bind(wx.EVT_CHOICE, self.selectUnit, self.unitSelector)
+        self.Bind(wx.EVT_CHOICE, self.selectUnit, self.unitChoice)
 
         # Stats table
         self.statGrid = wx.grid.Grid(
-          parent=self.unitInfo, id=wx.ID_ANY, pos=(0, 30), size=(165, 220)
+          parent=self.unitInfoBox, id=wx.ID_ANY, pos=(0, 30), size=(165, 220)
         )
         self.statGrid.CreateGrid(
           numRows=10, numCols=2,
@@ -170,61 +186,61 @@ class PanelOptimizer(wx.Panel):
         #self.unitContent.Add(self.statGrid)
 
         #Rune set list
-        runeListBox = [
+        runeBoxList = [
           wx.StaticBox(
-            parent=self.unitInfo, label="Slot1:", id=wx.ID_ANY,
+            parent=self.unitInfoBox, label="Slot1:", id=wx.ID_ANY,
             pos=(265, 30), size=(80, 115)
           ),
           wx.StaticBox(
-            parent=self.unitInfo, label="Slot2:", id=wx.ID_ANY,
+            parent=self.unitInfoBox, label="Slot2:", id=wx.ID_ANY,
             pos=(350, 30), size=(80, 115)
           ),
           wx.StaticBox(
-            parent=self.unitInfo, label="Slot3:", id=wx.ID_ANY,
+            parent=self.unitInfoBox, label="Slot3:", id=wx.ID_ANY,
             pos=(350, 150), size=(80, 115)
           ),
           wx.StaticBox(
-            parent=self.unitInfo, label="Slot4:", id=wx.ID_ANY,
+            parent=self.unitInfoBox, label="Slot4:", id=wx.ID_ANY,
             pos=(265, 150), size=(80, 115)
           ),
           wx.StaticBox(
-            parent=self.unitInfo, label="Slot5:", id=wx.ID_ANY,
+            parent=self.unitInfoBox, label="Slot5:", id=wx.ID_ANY,
             pos=(180, 150), size=(80, 115)
           ),
           wx.StaticBox(
-            parent=self.unitInfo, label="Slot6:", id=wx.ID_ANY,
+            parent=self.unitInfoBox, label="Slot6:", id=wx.ID_ANY,
             pos=(180, 30), size=(80, 115)
           )
         ]
-        self.runeList = [
+        self.runeLabelList = [
           wx.StaticText(
-            parent=runeListBox[0],  id=wx.ID_ANY, label="",
+            parent=runeBoxList[0],  id=wx.ID_ANY, label="",
             pos=(0, 0), size=(80, 115)
           ),
           wx.StaticText(
-            parent=runeListBox[1],  id=wx.ID_ANY, label="",
+            parent=runeBoxList[1],  id=wx.ID_ANY, label="",
             pos=(0, 0), size=(80, 115)
           ),
           wx.StaticText(
-            parent=runeListBox[2],  id=wx.ID_ANY, label="",
+            parent=runeBoxList[2],  id=wx.ID_ANY, label="",
             pos=(0, 0), size=(80, 115)
           ),
           wx.StaticText(
-            parent=runeListBox[3],  id=wx.ID_ANY, label="",
+            parent=runeBoxList[3],  id=wx.ID_ANY, label="",
             pos=(0, 0), size=(80, 115)
           ),
           wx.StaticText(
-            parent=runeListBox[4],  id=wx.ID_ANY, label="",
+            parent=runeBoxList[4],  id=wx.ID_ANY, label="",
             pos=(0, 0), size=(80, 115)
           ),
           wx.StaticText(
-            parent=runeListBox[5],  id=wx.ID_ANY, label="",
+            parent=runeBoxList[5],  id=wx.ID_ANY, label="",
             pos=(0, 0), size=(80, 115)
           )
         ]
         monospaceFont.PointSize -= 2
         for i in range(0, 6):
-            runeListBox[i].SetFont(monospaceFont)
+            runeBoxList[i].SetFont(monospaceFont)
         monospaceFont.PointSize += 2
 
         # Min stats
@@ -271,7 +287,7 @@ class PanelOptimizer(wx.Panel):
           parent=minStatBox, label="DMG", id=wx.ID_ANY,
           pos=(0, 225), size=(30, 25)
         )
-        self.minStatSlid = [
+        self.minStatSlidList = [
             wx.Slider(
               parent=minStatBox, id=wx.ID_ANY, pos=(30, 0),
               size=(120, 25), name="slid0"
@@ -314,13 +330,13 @@ class PanelOptimizer(wx.Panel):
             )
         ]
         for i in range(0, 10):
-            self.minStatSlid[i].SetMin(0)
-            self.minStatSlid[i].SetMax(0)
-            self.minStatSlid[i].SetValue(0)
+            self.minStatSlidList[i].SetMin(0)
+            self.minStatSlidList[i].SetMax(0)
+            self.minStatSlidList[i].SetValue(0)
             self.Bind(
-              wx.EVT_SCROLL, self.minStatChangeBySlider, self.minStatSlid[i]
+              wx.EVT_SCROLL, self.minStatChangeBySlider, self.minStatSlidList[i]
             )
-        self.minStatText = [
+        self.minStatTextList = [
             wx.TextCtrl(
               minStatBox, id=wx.ID_ANY, value="", pos=(155, 0), size=(65, 25),
               style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB
@@ -364,7 +380,8 @@ class PanelOptimizer(wx.Panel):
         ]
         for i in range(0, 9):
             self.Bind(
-              wx.EVT_TEXT_ENTER, self.minStatChangeByText, self.minStatText[i]
+              wx.EVT_TEXT_ENTER,
+              self.minStatChangeByText, self.minStatTextList[i]
             )
         minStatsReset = wx.Button(
           parent=minStatBox, id=wx.ID_ANY, pos=(10, 250),
@@ -374,7 +391,7 @@ class PanelOptimizer(wx.Panel):
           parent=minStatBox, id=wx.ID_ANY, pos=(120, 250),
           size=(100, 20), style=wx.LC_REPORT, label="Adapt all")
         # TODO: Add binds
-        self.optimizationOptions.Add(minStatBox)
+        self.optionsSizer.Add(minStatBox)
 
         # Allowed main stats for even slots
         names = [
@@ -385,7 +402,7 @@ class PanelOptimizer(wx.Panel):
           self, id=wx.ID_ANY, label="Main stats (2, 4, 6):",
           pos=(10, 300), size=(150, 190)
         )
-        self.stats = [
+        self.statCheckListList = [
           wx.CheckListBox(
             parent=statBox, id=wx.ID_ANY, pos=(5, 5),
             size=(70, 155), choices=names[0]
@@ -395,20 +412,20 @@ class PanelOptimizer(wx.Panel):
             size=(70, 155), choices=names[1]
           )
         ]
-        self.optimizationOptions.Add(statBox)
+        self.optionsSizer.Add(statBox)
 
         # Rune sets
         names = [
           "",        "ENERGY ", "GUARD  ", "SWIFT  ", "BLADE  ", "RAGE   ",
-          "FOCUS  ", "ENDURE ", "FATAL  ", "DESPAIR", "VAMPIRE", "VIOLENT",
-          "NEMESIS", "WILL   ", "SHIELD ", "REVENGE", "DESTROY", "FIGHT  ",
-          "DETERMI", "ENHANCE", "ACCURAC", "TOLERAN"
+          "FOCUS  ", "ENDURE ", "FATAL  ", "DESPAIR", "VAMPIRE",
+          "VIOLENT", "NEMESIS", "WILL   ", "SHIELD ", "REVENGE", "DESTROY",
+          "FIGHT  ", "DETERMI", "ENHANCE", "ACCURAC", "TOLERAN"
         ]
         setBox = wx.StaticBox(
           self, label="Rune Sets:", id=wx.ID_ANY,
           pos=(170, 300), size=(115, 120)
         )
-        self.runeSets = [
+        self.setChoiceList = [
             wx.Choice(
               parent=setBox, id=wx.ID_ANY, pos=(5, 0),
               size=(100, 30), choices=names
@@ -422,18 +439,18 @@ class PanelOptimizer(wx.Panel):
               size=(100, 30), choices=names
             )
         ]
-        self.optimizationOptions.Add(setBox)
+        self.optionsSizer.Add(setBox)
 
         # Rune level selector
         levelBox = wx.StaticBox(
           self, label="Rune Level:", id=wx.ID_ANY,
           pos=(170, 420), size=(115, 70)
         )
-        self.level = wx.Choice(
+        self.levelChoice = wx.Choice(
           parent=levelBox, id=wx.ID_ANY, pos=(5, 0),
           choices=["Current", "+ 12", " + 15"]
         )
-        self.optimizationOptions.Add(levelBox)
+        self.optionsSizer.Add(levelBox)
 
         # Team list
         teams = []
@@ -452,33 +469,73 @@ class PanelOptimizer(wx.Panel):
         )
 
         # Inventory only option
-        self.optimizationOptions.Add(teamsBox)
-        self.inventory = wx.CheckBox(
+        self.optionsSizer.Add(teamsBox)
+        self.inventoryCheck = wx.CheckBox(
           parent=self, id=wx.ID_ANY, label="Only runes in storage",
           pos=(560, 310), size=(180, 20)
         )
-        self.optimizationOptions.Add(self.inventory)
-        self.teams = wx.CheckListBox(
+        self.optionsSizer.Add(self.inventoryCheck)
+        self.teamCheckList = wx.CheckListBox(
+          parent=teamsBox, id=wx.ID_ANY,
+          pos=(5, 5), size=(250, 130), choices=teams
+        )
+        btAllTeams = wx.Button(
+          parent=teamsBox, id=wx.ID_ANY,
+          pos=(5, 135), size=(120, 20), label="Select all"
+        )
+        btNoTeams = wx.Button(
           parent=teamsBox, id=wx.ID_ANY,
-          pos=(5, 5), size=(250, 160), choices=teams
+          pos=(130, 135), size=(120, 20), label="Deselect all"
         )
+        self.Bind(wx.EVT_BUTTON, self.selectAllTeams, btAllTeams)
+        self.Bind(wx.EVT_BUTTON, self.deselectAllTeams, btNoTeams)
 
         # Button to start
         btOptimize = wx.Button(
           parent=self, id=wx.ID_ANY, pos=(600, 500),
           size=(100, 40), style=wx.LC_REPORT, label="OPTIMIZE"
         )
-        self.optimizationOptions.Add(btOptimize)
+        self.optionsSizer.Add(btOptimize)
         self.Bind(wx.EVT_BUTTON, self.startOptimization, btOptimize)
 
+        # Progress bar
+        self.progressGauge = wx.Gauge(
+          parent=self, id=wx.ID_ANY, range=20,
+          pos=(50, 485), size=(500, 40), style=wx.GA_HORIZONTAL
+        )
+
         # By default, hide all optimization options
-        self.optimizationOptions.ShowItems(False)
+        self.optionsSizer.ShowItems(False)
+
+    def selectAllTeams(self, event = None):
+        """Selects all teams in the list.
+
+        Parameters
+        ----------
+        event : wxEvent, optional
+            The event that triggered the call (default is None).
+
+        """
+        for i in range(0, len(self.teamIds)):
+            self.teamCheckList.Check(i, True)
+
+    def deselectAllTeams(self, event = None):
+        """Deselects all teams in the list.
+
+        Parameters
+        ----------
+        event : wxEvent, optional
+            The event that triggered the call (default is None).
+
+        """
+        for i in range(0, len(self.teamIds)):
+            self.teamCheckList.Check(i, False)
 
     def selectUnit(self, event = None):
         """Loads a unit info and enables optimizaton options.
 
-        Called when a unit is selected in unitSelector. If called from an
-        an event, the unit selected in unitSelector gets priority. When
+        Called when a unit is selected in unitChoice. If called from an
+        an event, the unit selected in unitChoice gets priority. When
         manually called, it uses unitId, so it must be set beforehand.
 
         Parameters
@@ -488,10 +545,21 @@ class PanelOptimizer(wx.Panel):
 
         """
 
+        # If its called from an event, it means a unit has been selected in this
+        # panel selector.
         if event != None:
             self.unitId = \
-              self.unidIdSelectorIndex[self.unitSelector.GetSelection()]
-            # TODO: Else mark selected in selector
+              self.unidIdSelectorIndex[self.unitChoice.GetSelection()]
+
+        # It it was not called from an event, it uses self.unitId and sets the
+        # selected unit in the unit selector automatically.
+        else:
+            for i in range(0, len(self.unidIdSelectorIndex)):
+                if self.unidIdSelectorIndex[i] == self.unitId:
+                    self.unitChoice.SetSelection(i)
+                    break
+
+        # Get the unit details
         cursor = conn.execute("""
           SELECT
             base_hp,
@@ -518,20 +586,20 @@ class PanelOptimizer(wx.Panel):
         """)
         row = cursor.fetchone()
         # First, set sliders max values
-        self.minStatSlid[0].SetMax(50000)  #HP
-        self.minStatSlid[1].SetMax(5000)   #ATK
-        self.minStatSlid[2].SetMax(5000)   #DEF
-        self.minStatSlid[3].SetMax(500)    #SPD
-        self.minStatSlid[4].SetMax(100)    #CRR
-        self.minStatSlid[5].SetMax(500)    #CRD
-        self.minStatSlid[6].SetMax(100)    #RES
-        self.minStatSlid[7].SetMax(85)     #ACC
-        self.minStatSlid[8].SetMax(250000) #EHP
-        self.minStatSlid[9].SetMax(8000)   #DMG
-        self.unitInfo.SetLabel(row[17] + " #" + row[16])
+        self.minStatSlidList[0].SetMax(50000)  #HP
+        self.minStatSlidList[1].SetMax(5000)   #ATK
+        self.minStatSlidList[2].SetMax(5000)   #DEF
+        self.minStatSlidList[3].SetMax(500)    #SPD
+        self.minStatSlidList[4].SetMax(100)    #CRR
+        self.minStatSlidList[5].SetMax(500)    #CRD
+        self.minStatSlidList[6].SetMax(100)    #RES
+        self.minStatSlidList[7].SetMax(85)     #ACC
+        self.minStatSlidList[8].SetMax(250000) #EHP
+        self.minStatSlidList[9].SetMax(8000)   #DMG
+        self.unitInfoBox.SetLabel(row[17] + " #" + row[16])
         for i in range(0, 8):
             value = str(row[i])
-            self.minStatSlid[i].SetMin(int(value))
+            self.minStatSlidList[i].SetMin(int(value))
             if i > 3:
                 value = value + "%"
             else:
@@ -539,8 +607,8 @@ class PanelOptimizer(wx.Panel):
             self.statGrid.SetCellValue(row=i, col=0, s=value)
         for i in range(0, 8):
             value = str(row[8 + i])
-            self.minStatSlid[i].SetValue(int(value))
-            self.minStatText[i].SetValue(value)
+            self.minStatSlidList[i].SetValue(int(value))
+            self.minStatTextList[i].SetValue(value)
             self.unitStats[i] = int(value)
             if i > 3:
                 value = value + "%"
@@ -552,14 +620,14 @@ class PanelOptimizer(wx.Panel):
         baseDef = int(self.statGrid.GetCellValue(row=2, col=0).replace("%", ""))
         baseEhp = math.ceil((((baseDef * 3.5) + 1140) * baseHp) / 1000)
         self.statGrid.SetCellValue(row=8, col=0, s=str(baseEhp))
-        self.minStatSlid[8].SetMin(baseEhp)
+        self.minStatSlidList[8].SetMin(baseEhp)
         currentHp = int(self.statGrid.GetCellValue(row=0, col=1))
         currentDef = \
           int(self.statGrid.GetCellValue(row=2, col=1).replace("%", ""))
         currentEhp = math.ceil((((currentDef * 3.5) + 1140) * currentHp) / 1000)
         self.statGrid.SetCellValue(row=8, col=1, s=str(currentEhp))
-        self.minStatSlid[8].SetValue(currentEhp)
-        self.minStatText[8].SetValue(str(currentEhp))
+        self.minStatSlidList[8].SetValue(currentEhp)
+        self.minStatTextList[8].SetValue(str(currentEhp))
         baseAtk = int(self.statGrid.GetCellValue(row=1, col=0))
         baseCrr = int(self.statGrid.GetCellValue(row=4, col=0).replace("%", ""))
         baseCrd = int(self.statGrid.GetCellValue(row=5, col=0).replace("%", ""))
@@ -571,7 +639,7 @@ class PanelOptimizer(wx.Panel):
           ((baseAtk + (baseAtk * baseCrd / 100)) * baseCrr / 100)
         )
         self.statGrid.SetCellValue(row=9, col=0, s=str(baseDmg))
-        self.minStatSlid[9].SetMin(baseDmg)
+        self.minStatSlidList[9].SetMin(baseDmg)
         currentAtk = int(self.statGrid.GetCellValue(row=1, col=1))
         currentCrr = \
           int(self.statGrid.GetCellValue(row=4, col=0).replace("%", ""))
@@ -585,12 +653,12 @@ class PanelOptimizer(wx.Panel):
           ((currentAtk + (currentAtk * currentCrd / 100)) * currentCrr / 100)
         )
         self.statGrid.SetCellValue(row=9, col=1, s=str(currentDmg))
-        self.minStatSlid[9].SetValue(currentDmg)
-        self.minStatText[9].SetValue(str(currentDmg))
+        self.minStatSlidList[9].SetValue(currentDmg)
+        self.minStatTextList[9].SetValue(str(currentDmg))
 
         # Populate the runes
         for i in range(0, 6):
-            self.runeList[i].SetLabel("")
+            self.runeLabelList[i].SetLabel("")
         cursor = conn.execute("""
           SELECT
             id, slot, type
@@ -633,35 +701,35 @@ class PanelOptimizer(wx.Panel):
                   stat_names[rowStats[1]] + str(rowStats[2]).rjust(4) + ""
                 if rowStats[3] > 0:
                     label = label + " +" + str(rowStats[3])
-            self.runeList[i].SetLabel(label)
+            self.runeLabelList[i].SetLabel(label)
             i = i + 1
 
         # Try to infer data to set the default options, reset the rest
         # Except the team list, rune level and storage: never reset those.
-        self.stats[0].SetCheckedItems(())
+        self.statCheckListList[0].SetCheckedItems(())
         for i in range(0, 3):
             if currEvenStats[i] == 1: # HP
-                self.stats[0].Check(0, True)
+                self.statCheckListList[0].Check(0, True)
             elif currEvenStats[i] == 2: # HP%
-                self.stats[0].Check(1, True)
+                self.statCheckListList[0].Check(1, True)
             elif currEvenStats[i] == 3: # ATK
-                self.stats[0].Check(2, True)
+                self.statCheckListList[0].Check(2, True)
             elif currEvenStats[i] == 4: # ATK%
-                self.stats[0].Check(3, True)
+                self.statCheckListList[0].Check(3, True)
             elif currEvenStats[i] == 5: # DEF
-                self.stats[0].Check(4, True)
+                self.statCheckListList[0].Check(4, True)
             elif currEvenStats[i] == 6: # DEF%
-                self.stats[0].Check(5, True)
+                self.statCheckListList[0].Check(5, True)
             elif currEvenStats[i] == 8: # SPD
-                self.stats[1].Check(0, True)
+                self.statCheckListList[1].Check(0, True)
             elif currEvenStats[i] == 9: # CRR
-                self.stats[1].Check(1, True)
+                self.statCheckListList[1].Check(1, True)
             elif currEvenStats[i] == 10: # CRD
-                self.stats[1].Check(2, True)
+                self.statCheckListList[1].Check(2, True)
             elif currEvenStats[i] == 11: # RES
-                self.stats[1].Check(3, True)
+                self.statCheckListList[1].Check(3, True)
             elif currEvenStats[i] == 12: # ACC
-                self.stats[1].Check(4, True)
+                self.statCheckListList[1].Check(4, True)
         currSetList = [-1, -1, -1]
         j = 0
         for i in range(0, 23):
@@ -679,16 +747,23 @@ class PanelOptimizer(wx.Panel):
                         currSetList[j] = i - 1
                         j += 1
                 # If a set of 4 has 4
-                else:
+                elif i in [3, 5, 8, 10, 11, 13]:
                     if currSets[i] >= 4:
                         currSetList[j] = i - 1
                         j += 1
+        # Rune set IDs 9 and 12 dont exist, so do a little trick with indexes.
         for i in range(0, 3):
-            if currSetList[i] != -1:
-                self.runeSets[i].SetSelection(currSetList[i])
+            #if currSetList[i] != 0:
+            actualId = currSetList[i] + 1
+            if (actualId > 8):
+                actualId -= 1
+            if (actualId > 11):
+                actualId -= 1
+            self.setChoiceList[i].SetSelection(actualId)
 
 
-        self.optimizationOptions.ShowItems(True)
+
+        self.optionsSizer.ShowItems(True)
 
     def startOptimization(self, event):
         """Prepares and runs a command optimization.
@@ -708,7 +783,7 @@ class PanelOptimizer(wx.Panel):
         command = "RuneOptimizer optimize "
         unitId = self.unitId
         command += unitId
-        level = self.level.GetSelection()
+        level = self.levelChoice.GetSelection()
         if level == 1:
             level = "12"
         elif level == 2:
@@ -719,8 +794,8 @@ class PanelOptimizer(wx.Panel):
         #print("    Rune level: " + level)
         sets = ""
         for i in range (0, 2):
-            selected = self.runeSets[i].GetString(
-              self.runeSets[i].GetSelection()
+            selected = self.setChoiceList[i].GetString(
+              self.setChoiceList[i].GetSelection()
             ).upper().replace(" ", "");
             for j in range(0, 22):
                 name = set_names[j].upper()
@@ -734,8 +809,9 @@ class PanelOptimizer(wx.Panel):
         command += (" --sets " + sets)
         stats = ""
         selected_stats = \
-          self.stats[0].GetCheckedItems() + self.stats[1].GetCheckedItems()
-        for s in self.stats[0].GetCheckedItems():
+          self.statCheckListList[0].GetCheckedItems() + \
+          self.statCheckListList[1].GetCheckedItems()
+        for s in self.statCheckListList[0].GetCheckedItems():
             if s == 0:
                 stats += "hpflat,"
             elif s == 1:
@@ -748,7 +824,7 @@ class PanelOptimizer(wx.Panel):
                 stats += "defflat,"
             elif s == 5:
                 stats += "def,"
-        for s in self.stats[1].GetCheckedItems():
+        for s in self.statCheckListList[1].GetCheckedItems():
             if s == 0:
                 stats += "spd,"
             elif s == 1:
@@ -765,35 +841,106 @@ class PanelOptimizer(wx.Panel):
         command += (" --stats " + stats)
         #print("    Main stats: " + stats)
 
-        command += (" --min-hp " + str(self.minStatSlid[0].GetValue()))
-        command += (" --min-atk " + str(self.minStatSlid[1].GetValue()))
-        command += (" --min-def " + str(self.minStatSlid[2].GetValue()))
-        command += (" --min-spd " + str(self.minStatSlid[3].GetValue()))
-        command += (" --min-crr " + str(self.minStatSlid[4].GetValue()))
-        command += (" --min-crd " + str(self.minStatSlid[5].GetValue()))
-        command += (" --min-res " + str(self.minStatSlid[6].GetValue()))
-        command += (" --min-acc " + str(self.minStatSlid[7].GetValue()))
-        command += (" --min-ehp " + str(self.minStatSlid[8].GetValue()))
-        command += (" --min-dmg " + str(self.minStatSlid[9].GetValue()))
-
-        if self.inventory.GetValue():
+        command += (" --min-hp " + str(self.minStatSlidList[0].GetValue()))
+        command += (" --min-atk " + str(self.minStatSlidList[1].GetValue()))
+        command += (" --min-def " + str(self.minStatSlidList[2].GetValue()))
+        command += (" --min-spd " + str(self.minStatSlidList[3].GetValue()))
+        command += (" --min-crr " + str(self.minStatSlidList[4].GetValue()))
+        command += (" --min-crd " + str(self.minStatSlidList[5].GetValue()))
+        command += (" --min-res " + str(self.minStatSlidList[6].GetValue()))
+        command += (" --min-acc " + str(self.minStatSlidList[7].GetValue()))
+        command += (" --min-ehp " + str(self.minStatSlidList[8].GetValue()))
+        command += (" --min-dmg " + str(self.minStatSlidList[9].GetValue()))
+
+        if self.inventoryCheck.GetValue():
             command += " --storage"
-        if len(self.teams.GetCheckedItems()) > 0:
+        if len(self.teamCheckList.GetCheckedItems()) > 0:
             command += " --no-teams "
-            for team in self.teams.GetCheckedItems():
+            for team in self.teamCheckList.GetCheckedItems():
                 command += str(self.teamIds[team]) + ","
             command = command[:-1]
 
 
         command += (" --gui ")
-        command = os.path.dirname(os.path.realpath(__file__)) + "/../../" + command
+        command = \
+          os.path.dirname(os.path.realpath(__file__)) + "/../../" + command
         print("Command: " + command)
 
-        out = subprocess.check_output(command.split())
-        json = bytes.decode(out)
+        self.progressGauge.SetValue(0)
+
+        # Timer ot periodically check on the process
+        self.timer = wx.Timer(self)
+        self.timer.Start(1000)
+        self.Bind(wx.EVT_TIMER, self.checkProcess)
+
+        # Create and execute the process
+        self.Bind(wx.EVT_END_PROCESS, self.optimizationComplete)
+        #print("Command: " + command)
+        self.process = wx.Process(self)
+        self.process.Redirect()
+        wx.Execute(command, wx.EXEC_ASYNC, self.process)
+
+    def checkProcess(self, event):
+        """Checks the process output and updates progress bar.
+
+        Parameters
+        ----------
+        event : wxEvent, optional
+            The event that triggered the call.
+
+        """
+        if self.process is not None:
+            stream = self.process.GetInputStream()
+            if stream.CanRead():
+                text = bytes.decode(stream.read())
+                text = text[:-1] # Remove the last newline
+
+                # Get only the last line
+                if text.rfind("\n") != -1:
+                    text = text[text.rfind("\n") + 1:]
+
+                # If the line is just a number, it's a progress indicator (1-20)
+                if text.isnumeric() and int(text) <= 20:
+                    self.progressGauge.SetValue(int(text))
+        else:
+            self.timer.Stop()
+
+    def optimizationComplete(self, event):
+        """Called when the update process is complete.
+
+        Hiddes the progress image, checks for errors in the output, prints a
+        message annd sets self.updateDone and self.updateError.
+
+        Parameters
+        ----------
+        event : wxEvent, optional
+            The event that triggered the call.
+
+        """
+
+        self.timer.Stop()
+        self.progressGauge.SetValue(20)
+
+        stream = self.process.GetInputStream()
+        jsonText = ""
+
+        if stream.CanRead():
+            text = bytes.decode(stream.read())
+            text = text[:-1] # Remove the last newline
+
+            # Get only the last line
+            if text.rfind("\n") != -1:
+                text = text[text.rfind("\n") + 1:]
+
+            jsonText = text
+
+        print('Finished. Result:\n' + text)
+
+        """
+
         # DEBUG: Sample data.
         #self.unitId = "7223811472"
-        #json = """{"result_count":5000,"results":[
+        #json = ""{"result_count":5000,"results":[
         #    {"id":0,"rating":215,"hp":20461,"atk":2521,"dfc":845,"spd":137,"crr":63,"crd":167,"res":29,"acc":15,"ehp":83839,"dmg":5174,"runes":["22677809846","22920616295","21755980400","25633344349","26207902579","28512560500"]},
         #    {"id":1,"rating":195,"hp":18876,"atk":2521,"dfc":853,"spd":137,"crr":60,"crd":174,"res":37,"acc":8,"ehp":77873,"dmg":5153,"runes":["22677809846","22920616295","27654723287","25633344349","26207902579","28512560500"]},
         #    {"id":2,"rating":185,"hp":17730,"atk":2521,"dfc":862,"spd":147,"crr":60,"crd":164,"res":28,"acc":15,"ehp":73704,"dmg":5002,"runes":["21564691276","22920616295","27654723287","25633344349","26207902579","22348038576"]},
@@ -801,13 +948,32 @@ class PanelOptimizer(wx.Panel):
         #    {"id":4,"rating":176,"hp":15319,"atk":2530,"dfc":909,"spd":142,"crr":60,"crd":165,"res":28,"acc":15,"ehp":66202,"dmg":5035,"runes":["21564691276","16759622995","27654723287","22750814840","26207902579","22348038576"]}]}
         #"""
 
+        print ("---- RESULT OUTPUT -------------------------------------------")
+        print(jsonText)
+        print ("--------------------------------------------------------------")
 
-        print ("---- OUTPUT ------------------------------------------------------------------------------------------")
-        print(json)
-        print ("------------------------------------------------------------------------------------------------------")
-
-        self.GetParent().frameResults.processResults(self.unitId, json)
-
+        if jsonText != "":
+            data = json.loads(
+              jsonText,
+              object_hook=lambda d: SimpleNamespace(**d)
+            )
+            if data.result_count == 0:
+                wx.MessageBox(
+                  parent=self,
+                  message="No results found for the current settings.",
+                  caption="No results found"
+                )
+            else:
+                self.GetParent().frameResults.processResults(
+                  self.unitId, jsonText
+                )
+                self.GetParent().ChangeSelection(3)
+        else:
+            wx.MessageBox(
+                  parent=self,
+                  message="No data received from RuneOptimizer.",
+                  caption="Error"
+                )
 
     def minStatChangeBySlider(self, event):
         """Changes text when a slider is changed.
@@ -822,7 +988,7 @@ class PanelOptimizer(wx.Panel):
         """
 
         slidId = int(event.GetEventObject().GetName().replace("slid", ""))
-        self.minStatText[slidId].SetValue(
+        self.minStatTextList[slidId].SetValue(
           str(event.GetEventObject().GetValue())
         )
 
@@ -840,15 +1006,15 @@ class PanelOptimizer(wx.Panel):
         textId = int(event.GetEventObject().GetName().replace("tx", ""))
         if event.GetEventObject().GetValue().isdigit() == False:
             event.GetEventObject().SetValue(
-              str(self.minStatSlid[textId].GetValue())
+              str(self.minStatSlidList[textId].GetValue())
             )
         value = int(event.GetEventObject().GetValue())
-        minValue = self.minStatSlid[textId].GetMin()
-        maxValue = self.minStatSlid[textId].GetMax()
+        minValue = self.minStatSlidList[textId].GetMin()
+        maxValue = self.minStatSlidList[textId].GetMax()
         if value < minValue:
             value = minValue
             event.GetEventObject().SetValue(str(value))
         elif value > maxValue:
             value = maxValue
             event.GetEventObject().SetValue(str(value))
-        self.minStatSlid[textId].SetValue(value)
+        self.minStatSlidList[textId].SetValue(value)

+ 151 - 148
src/RuneOptimizerGUI/classes/PanelResults.py

@@ -22,12 +22,10 @@ class PanelResults(wx.Panel):
 
     Parameters
     ----------
-    unitId : str
+    unitId : string
         ID of the unit being optimized (default "").
-    unitName : str
+    unitName : string
         Name of the unit being optimized (default "").
-    unitNameLabel : wx.StaticText
-        Labels for the unit name.
     data : Python Object
         Results from RuneOptimizer (default None).
     unitStats : int[10]
@@ -39,32 +37,36 @@ class PanelResults(wx.Panel):
         Number of pages of results (default 0).
     linesPerPage : int
         Number of results to show per page (default 10).
-    pgPrevBt : wx.Button
-        Button to go to the previous page.
-    pgPrevBt : wx.Button
-        Button to go to the previous page.
-    resultsPageIndicator : wx.StaticText
-        Label to indicate the current and maximum pages.
+    selectedResultndex : int
+        Selected result index (default -1).
+    unitNameLabel : wx.StaticText
+        Labels for the unit name.
+    tableSizer : wx.BoxSizer
+        Holds the result list. Hidden until processResults is called.
+    detailsSizer : wx.BoxSizer
+        Holds every widget that is hidden until a result is selected.
     resultGrid : wx.Grid.grid
         Table of results.
-    resultContent : wx.BoxSizer
-        Holds every widget that is hidden until a result is selected.
+    pgPrevButton : wx.Button
+        Button to go to the previous page.
+    pageLabel : wx.StaticText
+        Label to indicate the current and maximum pages.
+    pgPrevButton : wx.Button
+        Button to go to the previous page.
     statGrid : wx.Grid.grid
         Table to show the new stats with the selected result.
-    runeIds : wx.StaticText[6]
+    idLabelList : wx.StaticText[6]
         Labels with the IDs of the runes in the current result.
-    runeLocations : wx.StaticText[6]
+    locationLabelList : wx.StaticText[6]
         Labels with the locations of the runes in the current result.
-    runeSets : wx.StaticText[6]
+    setLabelList : wx.StaticText[6]
         Labels with the set names of the runes in the current result.
-    runeMains : wx.StaticText[6]
+    mainLabelList : wx.StaticText[6]
         Labels with the main stats of the runes in the current result.
-    runeInnates : wx.StaticText[6]
+    innateLabelList : wx.StaticText[6]
         Labels with the innates of the runes in the current result.
-    runeStats : wx.StaticText[6][4]
+    statLabelList : wx.StaticText[6][4]
         Labels with the stats of the runes in the current result.
-    selectedResultndex : int
-        Selected result index (default -1).
 
     Methods
     -------
@@ -74,8 +76,6 @@ class PanelResults(wx.Panel):
         Goes to the previous result page.
     pgNext(event)
         Goes to the next result page.
-    closeWindow(event)
-        Closes the frame.
     applyRunes(event)
         Applies the runes in the currently selected result.
     printResults()
@@ -89,25 +89,26 @@ class PanelResults(wx.Panel):
 
     unitId = ""
     unitName = ""
-    unitNameLabel = None
     data = None
     unitStats = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
     page = 0
     totalPages = 0
     linesPerPage = 10
-    pgPrevBt = None
-    pgNextBt = None
-    resultsPageIndicator = None
+    selectedResultIndex = -1
+    unitNameLabel = None
+    tableSizer = None
+    detailsSizer = None
     resultGrid = None
-    resultContent = None
+    pgPrevButton = None
+    pageLabel = None
+    pgNextButton = None
     statGrid = None
-    runeIds = None
-    runeLocations = None
-    runeSets = None
-    runeMains = None
-    runeInnates = None
-    runeStats = None
-    selectedResultIndex = -1
+    idLabelList = None
+    locationLabelList = None
+    setLabelList = None
+    mainLabelList = None
+    innateLabelList = None
+    statLabelList = None
 
     def __init__(self, parent, id=wx.ID_ANY):
         """Initializes the panel.
@@ -120,6 +121,10 @@ class PanelResults(wx.Panel):
         wx.Panel.__init__(self, parent=parent, id=id)
 
         # Prepare some fonts
+        titleFont = wx.Font(
+          pointSize=14, family=wx.FONTFAMILY_DEFAULT,
+          style=wx.FONTSTYLE_NORMAL, weight=wx.FONTWEIGHT_BOLD
+        )
         monospaceFont = wx.Font(
           pointSize=10, family=wx.FONTFAMILY_TELETYPE,
           style=wx.FONTSTYLE_NORMAL, weight=wx.FONTWEIGHT_NORMAL
@@ -138,11 +143,12 @@ class PanelResults(wx.Panel):
             parent=self, id=wx.ID_ANY, label="Nothing yet. Optimize something!",
             pos=(0, 0), size=(400, 30)
         )
+        self.unitNameLabel.SetFont(titleFont)
 
         # Contains the results table. Hidden until they are loaded.
-        self.resultContainer = wx.BoxSizer(wx.VERTICAL)
+        self.tableSizer = wx.BoxSizer(wx.VERTICAL)
         # Contains all thigs to be shown once a result is selected
-        self.resultContent = wx.BoxSizer(wx.VERTICAL)
+        self.detailsSizer = wx.BoxSizer(wx.VERTICAL)
 
         # The result list table
         self.resultGrid = wx.grid.Grid(
@@ -187,26 +193,26 @@ class PanelResults(wx.Panel):
         self.Bind(
           wx.grid.EVT_GRID_SELECT_CELL, self.resultSelected, self.resultGrid
         )
-        self.resultContainer.Add(self.resultGrid)
+        self.tableSizer.Add(self.resultGrid)
 
         # Paginator
-        self.pgPrevBt = wx.Button(
+        self.pgPrevButton = wx.Button(
           parent=self, id=wx.ID_ANY, pos=(530, 30), size=(40, 50),
           style=wx.LC_REPORT, label="Prev\npage"
         )
-        self.resultContainer.Add(self.pgPrevBt)
-        self.resultsPageIndicator = wx.StaticText(
+        self.tableSizer.Add(self.pgPrevButton)
+        self.pageLabel = wx.StaticText(
           parent=self,id=wx.ID_ANY, pos=(530, 80), size=(40, 15),
           style=wx.ALIGN_CENTRE_HORIZONTAL, label="1/1"
         )
-        self.resultContainer.Add(self.resultsPageIndicator)
-        self.pgNextBt = wx.Button(
+        self.tableSizer.Add(self.pageLabel)
+        self.pgNextButton = wx.Button(
           parent=self, id=wx.ID_ANY, pos=(530, 100), size=(40, 50),
           style=wx.LC_REPORT, label="Next\npage"
         )
-        self.resultContainer.Add(self.pgNextBt)
-        self.Bind(wx.EVT_BUTTON, self.pgPrev, self.pgPrevBt)
-        self.Bind(wx.EVT_BUTTON, self.pgNext, self.pgNextBt)
+        self.tableSizer.Add(self.pgNextButton)
+        self.Bind(wx.EVT_BUTTON, self.pgPrev, self.pgPrevButton)
+        self.Bind(wx.EVT_BUTTON, self.pgNext, self.pgNextButton)
 
         # Stats table
         self.statGrid = wx.grid.Grid(
@@ -247,11 +253,11 @@ class PanelResults(wx.Panel):
         self.statGrid.SetRowLabelValue(row=7, value="ACC")
         self.statGrid.SetRowLabelValue(row=8, value="EHP")
         self.statGrid.SetRowLabelValue(row=9, value="DMG")
-        self.resultContent.Add(self.statGrid)
+        self.detailsSizer.Add(self.statGrid)
 
         #Rune set list
         monospaceFont.PointSize -= 2
-        runeListBox = [
+        rubeBoxList = [
           wx.StaticBox(
             parent=self, label="Slot1:",id=wx.ID_ANY,
             pos=(350, 210), size=(140, 160)
@@ -278,277 +284,277 @@ class PanelResults(wx.Panel):
           )
         ]
         for i in range(0, 6):
-            runeListBox[i].SetFont(monospaceFont)
-            self.resultContent.Add(runeListBox[i])
+            rubeBoxList[i].SetFont(monospaceFont)
+            self.detailsSizer.Add(rubeBoxList[i])
 
-        self.runeIds = [
+        self.idLabelList = [
           wx.StaticText(
-            runeListBox[0], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
+            rubeBoxList[0], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[1], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
+            rubeBoxList[1], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[2], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
+            rubeBoxList[2], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[3], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
+            rubeBoxList[3], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[4], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
+            rubeBoxList[4], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[5], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
+            rubeBoxList[5], id=wx.ID_ANY, label="", pos=(5, 0), size=(120, 10)
           )
         ]
 
-        self.runeLocations = [
+        self.locationLabelList = [
           wx.StaticText(
-            runeListBox[0], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
+            rubeBoxList[0], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[1], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
+            rubeBoxList[1], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[2], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
+            rubeBoxList[2], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[3], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
+            rubeBoxList[3], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[4], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
+            rubeBoxList[4], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[5], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
+            rubeBoxList[5], id=wx.ID_ANY, label="", pos=(5, 15), size=(120, 10)
           ),
         ]
 
-        self.runeSets = [
+        self.setLabelList = [
           wx.StaticText(
-            runeListBox[0], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
+            rubeBoxList[0], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[1], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
+            rubeBoxList[1], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[2], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
+            rubeBoxList[2], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[3], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
+            rubeBoxList[3], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[4], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
+            rubeBoxList[4], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
           ),
           wx.StaticText(
-            runeListBox[5], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
+            rubeBoxList[5], id=wx.ID_ANY, label="", pos=(5, 30), size=(120, 10)
           ),
         ]
 
         wx.StaticLine(
-          parent=runeListBox[0], id=wx.ID_ANY,
+          parent=rubeBoxList[0], id=wx.ID_ANY,
           pos=(5, 45), size=(130, 1), style=wx.LC_REPORT
         )
         wx.StaticLine(
-          parent=runeListBox[1], id=wx.ID_ANY,
+          parent=rubeBoxList[1], id=wx.ID_ANY,
           pos=(5, 45), size=(130, 1), style=wx.LC_REPORT
         )
         wx.StaticLine(
-          parent=runeListBox[2], id=wx.ID_ANY,
+          parent=rubeBoxList[2], id=wx.ID_ANY,
           pos=(5, 45), size=(130, 1), style=wx.LC_REPORT
         )
         wx.StaticLine(
-          parent=runeListBox[3], id=wx.ID_ANY,
+          parent=rubeBoxList[3], id=wx.ID_ANY,
           pos=(5, 45), size=(130, 1), style=wx.LC_REPORT
         )
         wx.StaticLine(
-          parent=runeListBox[4], id=wx.ID_ANY,
+          parent=rubeBoxList[4], id=wx.ID_ANY,
           pos=(5, 45), size=(130, 1), style=wx.LC_REPORT
         )
         wx.StaticLine(
-          parent=runeListBox[5], id=wx.ID_ANY,
+          parent=rubeBoxList[5], id=wx.ID_ANY,
           pos=(5, 45), size=(130, 1), style=wx.LC_REPORT
         )
 
-        self.runeMains = [
+        self.mainLabelList = [
           wx.StaticText(
-            parent=runeListBox[0], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[0], id=wx.ID_ANY, label="",
             pos=(5, 50), size=(120, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[1], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[1], id=wx.ID_ANY, label="",
             pos=(5, 50), size=(120, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[2], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[2], id=wx.ID_ANY, label="",
             pos=(5, 50), size=(120, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[3], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[3], id=wx.ID_ANY, label="",
             pos=(5, 50), size=(120, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[4], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[4], id=wx.ID_ANY, label="",
             pos=(5, 50), size=(120, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[5], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[5], id=wx.ID_ANY, label="",
             pos=(5, 50), size=(120, 10)
           ),
         ]
         for i in range(0, 6):
-            self.runeMains[i].SetFont(monospaceFontBold)
+            self.mainLabelList[i].SetFont(monospaceFontBold)
 
-        self.runeInnates = [
+        self.innateLabelList = [
           wx.StaticText(
-            parent=runeListBox[0], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[0], id=wx.ID_ANY, label="",
             pos=(5, 65), size=(120, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[1], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[1], id=wx.ID_ANY, label="",
             pos=(5, 65), size=(120, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[2], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[2], id=wx.ID_ANY, label="",
             pos=(5, 65), size=(120, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[3], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[3], id=wx.ID_ANY, label="",
             pos=(5, 65), size=(120, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[4], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[4], id=wx.ID_ANY, label="",
             pos=(5, 65), size=(120, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[5], id=wx.ID_ANY, label="",
+            parent=rubeBoxList[5], id=wx.ID_ANY, label="",
             pos=(5, 65), size=(120, 10)
           )
         ]
         for i in range(0, 6):
-            self.runeInnates[i].SetFont(monospaceFontItalic)
+            self.innateLabelList[i].SetFont(monospaceFontItalic)
 
-        self.runeStats = [
+        self.statLabelList = [
           [
             wx.StaticText(
-              parent=runeListBox[0], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[0], id=wx.ID_ANY, label="",
               pos=(5, 80), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[0], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[0], id=wx.ID_ANY, label="",
               pos=(5, 95), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[0], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[0], id=wx.ID_ANY, label="",
               pos=(5, 110), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[0], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[0], id=wx.ID_ANY, label="",
               pos=(5, 125), size=(120, 10)
             )
           ],
           [
             wx.StaticText(
-              parent=runeListBox[1], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[1], id=wx.ID_ANY, label="",
               pos=(5, 80), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[1], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[1], id=wx.ID_ANY, label="",
               pos=(5, 95), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[1], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[1], id=wx.ID_ANY, label="",
               pos=(5, 110), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[1], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[1], id=wx.ID_ANY, label="",
               pos=(5, 125), size=(120, 10)
             )
           ],
           [
             wx.StaticText(
-              parent=runeListBox[2], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[2], id=wx.ID_ANY, label="",
               pos=(5, 80), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[2], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[2], id=wx.ID_ANY, label="",
               pos=(5, 95), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[2], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[2], id=wx.ID_ANY, label="",
               pos=(5, 110), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[2], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[2], id=wx.ID_ANY, label="",
               pos=(5, 125), size=(120, 10)
             )
           ],
           [
             wx.StaticText(
-              parent=runeListBox[3], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[3], id=wx.ID_ANY, label="",
               pos=(5, 80), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[3], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[3], id=wx.ID_ANY, label="",
               pos=(5, 95), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[3], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[3], id=wx.ID_ANY, label="",
               pos=(5, 110), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[3], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[3], id=wx.ID_ANY, label="",
               pos=(5, 125), size=(120, 10)
             )
           ],
           [
             wx.StaticText(
-              parent=runeListBox[4], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[4], id=wx.ID_ANY, label="",
               pos=(5, 80), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[4], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[4], id=wx.ID_ANY, label="",
               pos=(5, 95), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[4], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[4], id=wx.ID_ANY, label="",
               pos=(5, 110), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[4], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[4], id=wx.ID_ANY, label="",
               pos=(5, 125), size=(120, 10)
             )
           ],
           [
             wx.StaticText(
-              parent=runeListBox[5], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[5], id=wx.ID_ANY, label="",
               pos=(5, 80), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[5], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[5], id=wx.ID_ANY, label="",
               pos=(5, 95), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[5], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[5], id=wx.ID_ANY, label="",
               pos=(5, 110), size=(120, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[5], id=wx.ID_ANY, label="",
+              parent=rubeBoxList[5], id=wx.ID_ANY, label="",
               pos=(5, 125), size=(120, 10)
             )
           ],
         ]
 
         # Action buttons
-        applyBt = wx.Button(
+        applyButton = wx.Button(
           parent=self, id=wx.ID_ANY, pos=(10, 450), size=(165, 60),
           style=wx.LC_REPORT, label="Apply runes"
         )
-        self.Bind(wx.EVT_BUTTON, self.applyRunes, applyBt)
-        self.resultContent.Add(applyBt)
+        self.Bind(wx.EVT_BUTTON, self.applyRunes, applyButton)
+        self.detailsSizer.Add(applyButton)
 
         # By default, hide everything TODO
-        self.resultContainer.ShowItems(False)
-        self.resultContent.ShowItems(False)
+        self.tableSizer.ShowItems(False)
+        self.detailsSizer.ShowItems(False)
 
     def processResults(self, unitId=None, jsonData=""):
         """Processes data obtained from RuneOptimizer.
@@ -654,9 +660,6 @@ class PanelResults(wx.Panel):
         if (self.selectedResultIndex < 0):
             # TODO: Show error
             return;
-        print("self.selectedResultIndex: " + str(self.selectedResultIndex))
-        #for i in range(0, 6):
-        #    print(self.data.results[self.selectedResultIndex].runes[i])
         # First, unassign all runes currently assigned to the unit
         cursor = conn.execute(
           """
@@ -754,16 +757,16 @@ class PanelResults(wx.Panel):
         after changing pages or processing data.
         """
 
-        self.pgPrevBt.Enable(True)
-        self.pgNextBt.Enable(True)
+        self.pgPrevButton.Enable(True)
+        self.pgNextButton.Enable(True)
         if self.totalPages == 1:
-            self.pgPrevBt.Enable(False)
-            self.pgNextBt.Enable(False)
+            self.pgPrevButton.Enable(False)
+            self.pgNextButton.Enable(False)
         elif self.page == 0:
-            self.pgPrevBt.Enable(False)
+            self.pgPrevButton.Enable(False)
         elif self.page + 1 == self.totalPages:
-            self.pgNextBt.Enable(False)
-        self.resultsPageIndicator.SetLabel(
+            self.pgNextButton.Enable(False)
+        self.pageLabel.SetLabel(
           str(self.page + 1) + "/" + str(self.totalPages)
         )
         for i in range(0, 10):
@@ -791,7 +794,7 @@ class PanelResults(wx.Panel):
         self.unitNameLabel.SetLabel(self.unitName + "    #" + self.unitId)
 
         # Make the table visible
-        self.resultContainer.ShowItems(True)
+        self.tableSizer.ShowItems(True)
 
     def resultSelected(self, event):
         """Populates and shows the runes and effective stats with the
@@ -1029,17 +1032,17 @@ class PanelResults(wx.Panel):
         else:
             self.statGrid.SetCellValue(row=9, col=1, s="")
 
-        self.resultContent.ShowItems(True)
+        self.detailsSizer.ShowItems(True)
 
         # Clean the runes
         for i in range(0, 5):
-            self.runeIds[i].SetLabel("")
-            self.runeLocations[i].SetLabel("")
-            self.runeSets[i].SetLabel("")
-            self.runeMains[i].SetLabel("")
-            self.runeInnates[i].SetLabel("")
+            self.idLabelList[i].SetLabel("")
+            self.locationLabelList[i].SetLabel("")
+            self.setLabelList[i].SetLabel("")
+            self.mainLabelList[i].SetLabel("")
+            self.innateLabelList[i].SetLabel("")
             for j in range(0, 3):
-                self.runeStats[i][j].SetLabel("")
+                self.statLabelList[i][j].SetLabel("")
 
         # Display the runes
         cursor = conn.execute(
@@ -1067,14 +1070,14 @@ class PanelResults(wx.Panel):
         i = 0
         for row in cursor:
             # Rows are 21 charactes width
-            self.runeIds[i].SetLabel(("#" + str(row[0])).rjust(21, " "))
+            self.idLabelList[i].SetLabel(("#" + str(row[0])).rjust(21, " "))
             if row[4] == None:
-                self.runeLocations[i].SetLabel("Storage")
+                self.locationLabelList[i].SetLabel("Storage")
             else:
-                self.runeLocations[i].SetLabel(
+                self.locationLabelList[i].SetLabel(
                   str(row[5])[0:9].ljust(9, " ") + " #" + str(row[4]) + ""
                 )
-            self.runeSets[i].SetLabel(
+            self.setLabelList[i].SetLabel(
               set_names[row[2]].ljust(18, " ") + "+" + str(row[3])
             )
             #print(self.data.results[self.selectedResultIndex].runes[i])
@@ -1115,12 +1118,12 @@ class PanelResults(wx.Panel):
                         value = value + "%"
                 line = name + value
                 if slot == -1: # main
-                    self.runeMains[i].SetLabel(line)
+                    self.mainLabelList[i].SetLabel(line)
                 elif slot == 0: # innate
-                    self.runeInnates[i].SetLabel(line)
+                    self.innateLabelList[i].SetLabel(line)
                 else: # normal stats
-                    self.runeStats[i][slot - 1].SetLabel(line)
+                    self.statLabelList[i][slot - 1].SetLabel(line)
             i += 1
 
         # Make the info visible
-        self.resultContent.ShowItems(True)
+        self.detailsSizer.ShowItems(True)

+ 145 - 118
src/RuneOptimizerGUI/classes/PanelUnits.py

@@ -22,33 +22,39 @@ class PanelUnits(wx.Panel):
 
     Parameters
     ----------
+    selecterId : string
+        ID of the currently selected unit.
     unitList : wx.ListCtrl
         Selectable unit list with priorities.
-    filterName : wx.TextCtrl
+    filterNameText : wx.TextCtrl
         Text input to filter units names.
-    filterNames : wx.CheckBox
+    filterNameTexts : wx.CheckBox
         Checkbox to include or exclude units in storage.
-    filterNoRunes : wx.CheckBox
+    filterNoRunesCheck : wx.CheckBox
         Checkbox to include or exclude units without runes.
-    filterNoTeams : wx.CheckBox
+    filterNoTeamsCheck : wx.CheckBox
         Checkbox to include or exclude units in no teams.
+    detailsSizer : wx.BoxSizer
+        Hold the unit detail elements. Hidden until unit selction.
     statGrid : wx.Grid.grid
         Table with the unit base and current stats.
-    runeSets : wx.StaticText[6]
+    setLabelList : wx.StaticText[6]
         Labels with the set of the runes of the selected unit.
-    runeIds : wx.StaticText[6]
+    idLabelList : wx.StaticText[6]
         Labels with the IDs of the runes of the selected unit.
-    runeMains : wx.StaticText[6]
+    mainLabelList : wx.StaticText[6]
         Labels with the main stats of the runes of the selected unit.
-    runeInnates : wx.StaticText[6]
+    innateLabelList : wx.StaticText[6]
         Labels with the innates of the runes of the selected unit.
-    runeStats : wx.StaticText[6][4]
+    statLabelList : wx.StaticText[6][4]
         Labels with the stats of the runes of the selected unit.
 
     Methods
     -------
     populateUnitList(event)
         Populates the unit list.
+    goToOptimizer(event)
+        Prepares the optimizer panel with the selected unit and redirects.
     unitSelected(event)
         Loads a unit info.
     processResults(jsonData)
@@ -56,17 +62,19 @@ class PanelUnits(wx.Panel):
 
     """
 
+    selectedId = None
     unitList = None
-    filterName = None
-    filterStorage = None
-    filterNoRunes = None
-    filterNoTeams = None
+    filterNameText = None
+    filterStorageCheck = None
+    filterNoRunesCheck = None
+    filterNoTeamsCheck = None
+    detailsSizer = None
     statGrid = None
-    runeSets = None
-    runeIds = None
-    runeMains = None
-    runeInnates = None
-    runeStats = None
+    setLabelList = None
+    idLabelList = None
+    mainLabelList = None
+    innateLabelList = None
+    statLabelList = None
 
     def __init__(self, parent, id=wx.ID_ANY):
         """Initializes the panel.
@@ -116,36 +124,47 @@ class PanelUnits(wx.Panel):
         wx.StaticText(
           parent=filterBox, label="Monster name", pos=(5, 5), size=(180, 20)
         )
-        self.filterName = wx.TextCtrl(
+        self.filterNameText = wx.TextCtrl(
           parent=filterBox, id=wx.ID_ANY, value="", pos=(5, 25),
           size=(177, 20), style=wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB
         )
-        self.Bind(wx.EVT_TEXT_ENTER, self.populateUnitList, self.filterName)
-        self.filterStorage = wx.CheckBox(
+        self.Bind(wx.EVT_TEXT_ENTER, self.populateUnitList, self.filterNameText)
+        self.filterStorageCheck = wx.CheckBox(
           parent=filterBox, id=wx.ID_ANY,
           label="Monsters in storage", pos=(5, 55), size=(180, 20)
         )
-        self.filterStorage.SetValue(True)
-        self.Bind(wx.EVT_CHECKBOX, self.populateUnitList, self.filterStorage)
-        self.filterNoRunes = wx.CheckBox(
+        self.filterStorageCheck.SetValue(True)
+        self.Bind(
+          wx.EVT_CHECKBOX, self.populateUnitList, self.filterStorageCheck
+        )
+        self.filterNoRunesCheck = wx.CheckBox(
           parent=filterBox, id=wx.ID_ANY,
           label="Monsters without runes", pos=(5, 75), size=(180, 20)
         )
-        self.filterNoRunes.SetValue(True)
-        self.Bind(wx.EVT_CHECKBOX, self.populateUnitList, self.filterNoRunes)
-        self.filterNoTeams = wx.CheckBox(
+        self.filterNoRunesCheck.SetValue(True)
+        self.Bind(
+          wx.EVT_CHECKBOX, self.populateUnitList, self.filterNoRunesCheck
+        )
+        self.filterNoTeamsCheck = wx.CheckBox(
           parent=filterBox, id=wx.ID_ANY,
           label="Monsters not in teams", pos=(5, 95), size=(180, 20)
         )
-        self.filterNoTeams.SetValue(True)
-        self.Bind(wx.EVT_CHECKBOX, self.populateUnitList, self.filterNoTeams)
+        self.filterNoTeamsCheck.SetValue(True)
+        self.Bind(
+          wx.EVT_CHECKBOX, self.populateUnitList, self.filterNoTeamsCheck
+        )
 
         self.populateUnitList(None)
 
+        # Sizer for all the unit details. It will be hidden until a unit is
+        # selected.
+        self.detailsSizer = wx.BoxSizer(wx.VERTICAL)
+
         # Stats table
         self.statGrid = wx.grid.Grid(
           parent=self, id=wx.ID_ANY, pos=(210, 260), size=(165, 220)
         )
+        self.detailsSizer.Add(self.statGrid)
         self.statGrid.CreateGrid(
           numRows=10, numCols=2,
           selmode=wx.grid.Grid.GridSelectionModes.SelectRowsOrColumns
@@ -185,7 +204,7 @@ class PanelUnits(wx.Panel):
         # Rune list
         # Decrease fonts for rune tables
         monospaceFont.PointSize -= 2
-        runeListBox = [
+        runeBoxList = [
           wx.StaticBox(
             parent=self, label="Slot1:",id=wx.ID_ANY,
             pos=(500, 255), size=(105, 110)
@@ -212,256 +231,266 @@ class PanelUnits(wx.Panel):
           )
         ]
         for i in range(0, 6):
-            runeListBox[i].SetFont(monospaceFont)
-            #self.resultContent.Add(runeListBox[i])
+            runeBoxList[i].SetFont(monospaceFont)
+            self.detailsSizer.Add(runeBoxList[i])
 
-        self.runeSets = [
+        self.setLabelList = [
           wx.StaticText(
-            parent=runeListBox[0], id=wx.ID_ANY, label="",
+            parent=runeBoxList[0], id=wx.ID_ANY, label="",
             pos=(0, 0), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[1], id=wx.ID_ANY, label="",
+            parent=runeBoxList[1], id=wx.ID_ANY, label="",
             pos=(0, 0), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[2], id=wx.ID_ANY, label="",
+            parent=runeBoxList[2], id=wx.ID_ANY, label="",
             pos=(0, 0), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[3], id=wx.ID_ANY, label="",
+            parent=runeBoxList[3], id=wx.ID_ANY, label="",
             pos=(0, 0), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[4], id=wx.ID_ANY, label="",
+            parent=runeBoxList[4], id=wx.ID_ANY, label="",
             pos=(0, 0), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[5], id=wx.ID_ANY, label="",
+            parent=runeBoxList[5], id=wx.ID_ANY, label="",
             pos=(0, 0), size=(105, 10)
           ),
         ]
 
-        self.runeIds = [
+        self.idLabelList = [
           wx.StaticText(
-            parent=runeListBox[0], id=wx.ID_ANY, label="",
+            parent=runeBoxList[0], id=wx.ID_ANY, label="",
             pos=(0, 10), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[1], id=wx.ID_ANY, label="",
+            parent=runeBoxList[1], id=wx.ID_ANY, label="",
             pos=(0, 10), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[2], id=wx.ID_ANY, label="",
+            parent=runeBoxList[2], id=wx.ID_ANY, label="",
             pos=(0, 10), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[3], id=wx.ID_ANY, label="",
+            parent=runeBoxList[3], id=wx.ID_ANY, label="",
             pos=(0, 10), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[4], id=wx.ID_ANY, label="",
+            parent=runeBoxList[4], id=wx.ID_ANY, label="",
             pos=(0, 10), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[5], id=wx.ID_ANY, label="",
+            parent=runeBoxList[5], id=wx.ID_ANY, label="",
             pos=(0, 10), size=(105, 10)
           )
         ]
         wx.StaticLine(
-          parent=runeListBox[0], id=wx.ID_ANY,
+          parent=runeBoxList[0], id=wx.ID_ANY,
           pos=(0, 20), size=(105, 1), style=wx.LC_REPORT
         )
         wx.StaticLine(
-          parent=runeListBox[1], id=wx.ID_ANY,
+          parent=runeBoxList[1], id=wx.ID_ANY,
           pos=(0, 20), size=(105, 1), style=wx.LC_REPORT
         )
         wx.StaticLine(
-          parent=runeListBox[2], id=wx.ID_ANY,
+          parent=runeBoxList[2], id=wx.ID_ANY,
           pos=(0, 20), size=(105, 1), style=wx.LC_REPORT
         )
         wx.StaticLine(
-          parent=runeListBox[3], id=wx.ID_ANY,
+          parent=runeBoxList[3], id=wx.ID_ANY,
           pos=(0, 20), size=(105, 1), style=wx.LC_REPORT
         )
         wx.StaticLine(
-          parent=runeListBox[4], id=wx.ID_ANY,
+          parent=runeBoxList[4], id=wx.ID_ANY,
           pos=(0, 20), size=(105, 1), style=wx.LC_REPORT
         )
         wx.StaticLine(
-          parent=runeListBox[5], id=wx.ID_ANY,
+          parent=runeBoxList[5], id=wx.ID_ANY,
           pos=(0, 20), size=(105, 1), style=wx.LC_REPORT
         )
 
-        self.runeMains = [
+        self.mainLabelList = [
           wx.StaticText(
-            parent=runeListBox[0], id=wx.ID_ANY, label="",
+            parent=runeBoxList[0], id=wx.ID_ANY, label="",
             pos=(0, 30), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[1], id=wx.ID_ANY, label="",
+            parent=runeBoxList[1], id=wx.ID_ANY, label="",
             pos=(0, 30), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[2], id=wx.ID_ANY, label="",
+            parent=runeBoxList[2], id=wx.ID_ANY, label="",
             pos=(0, 30), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[3], id=wx.ID_ANY, label="",
+            parent=runeBoxList[3], id=wx.ID_ANY, label="",
             pos=(0, 30), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[4], id=wx.ID_ANY, label="",
+            parent=runeBoxList[4], id=wx.ID_ANY, label="",
             pos=(0, 30), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[5], id=wx.ID_ANY, label="",
+            parent=runeBoxList[5], id=wx.ID_ANY, label="",
             pos=(0, 30), size=(105, 10)
           )
         ]
         for i in range(0, 6):
-            self.runeMains[i].SetFont(monospaceFontBold)
+            self.mainLabelList[i].SetFont(monospaceFontBold)
 
-        self.runeInnates = [
+        self.innateLabelList = [
           wx.StaticText(
-            parent=runeListBox[0], id=wx.ID_ANY, label="",
+            parent=runeBoxList[0], id=wx.ID_ANY, label="",
             pos=(0, 40), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[1], id=wx.ID_ANY, label="",
+            parent=runeBoxList[1], id=wx.ID_ANY, label="",
             pos=(0, 40), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[2], id=wx.ID_ANY, label="",
+            parent=runeBoxList[2], id=wx.ID_ANY, label="",
             pos=(0, 40), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[3], id=wx.ID_ANY, label="",
+            parent=runeBoxList[3], id=wx.ID_ANY, label="",
             pos=(0, 40), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[4], id=wx.ID_ANY, label="",
+            parent=runeBoxList[4], id=wx.ID_ANY, label="",
             pos=(0, 40), size=(105, 10)
           ),
           wx.StaticText(
-            parent=runeListBox[5], id=wx.ID_ANY, label="",
+            parent=runeBoxList[5], id=wx.ID_ANY, label="",
             pos=(0, 40), size=(105, 10)
           )
         ]
         for i in range(0, 6):
-            self.runeInnates[i].SetFont(monospaceFontItalic)
+            self.innateLabelList[i].SetFont(monospaceFontItalic)
 
-        self.runeStats = [
+        self.statLabelList = [
           [
             wx.StaticText(
-              parent=runeListBox[0], id=wx.ID_ANY, label="",
+              parent=runeBoxList[0], id=wx.ID_ANY, label="",
               pos=(0, 50), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[0], id=wx.ID_ANY, label="",
+              parent=runeBoxList[0], id=wx.ID_ANY, label="",
               pos=(0, 60), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[0], id=wx.ID_ANY, label="",
+              parent=runeBoxList[0], id=wx.ID_ANY, label="",
               pos=(0, 70), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[0], id=wx.ID_ANY, label="",
+              parent=runeBoxList[0], id=wx.ID_ANY, label="",
               pos=(0, 80), size=(105, 10)
             )
           ],
           [
             wx.StaticText(
-              parent=runeListBox[1], id=wx.ID_ANY, label="",
+              parent=runeBoxList[1], id=wx.ID_ANY, label="",
               pos=(0, 50), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[1], id=wx.ID_ANY, label="",
+              parent=runeBoxList[1], id=wx.ID_ANY, label="",
               pos=(0, 60), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[1], id=wx.ID_ANY, label="",
+              parent=runeBoxList[1], id=wx.ID_ANY, label="",
               pos=(0, 70), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[1], id=wx.ID_ANY, label="",
+              parent=runeBoxList[1], id=wx.ID_ANY, label="",
               pos=(0, 80), size=(105, 10)
             )
           ],
           [
             wx.StaticText(
-              parent=runeListBox[2], id=wx.ID_ANY, label="",
+              parent=runeBoxList[2], id=wx.ID_ANY, label="",
               pos=(0, 50), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[2], id=wx.ID_ANY, label="",
+              parent=runeBoxList[2], id=wx.ID_ANY, label="",
               pos=(0, 60), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[2], id=wx.ID_ANY, label="",
+              parent=runeBoxList[2], id=wx.ID_ANY, label="",
               pos=(0, 70), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[2], id=wx.ID_ANY, label="",
+              parent=runeBoxList[2], id=wx.ID_ANY, label="",
               pos=(0, 80), size=(105, 10)
             )
           ],
           [
             wx.StaticText(
-              parent=runeListBox[3], id=wx.ID_ANY, label="",
+              parent=runeBoxList[3], id=wx.ID_ANY, label="",
               pos=(0, 50), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[3], id=wx.ID_ANY, label="",
+              parent=runeBoxList[3], id=wx.ID_ANY, label="",
               pos=(0, 60), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[3], id=wx.ID_ANY, label="",
+              parent=runeBoxList[3], id=wx.ID_ANY, label="",
               pos=(0, 70), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[3], id=wx.ID_ANY, label="",
+              parent=runeBoxList[3], id=wx.ID_ANY, label="",
               pos=(0, 80), size=(105, 10)
             )
           ],
           [
             wx.StaticText(
-              parent=runeListBox[4], id=wx.ID_ANY, label="",
+              parent=runeBoxList[4], id=wx.ID_ANY, label="",
               pos=(0, 50), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[4], id=wx.ID_ANY, label="",
+              parent=runeBoxList[4], id=wx.ID_ANY, label="",
               pos=(0, 60), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[4], id=wx.ID_ANY, label="",
+              parent=runeBoxList[4], id=wx.ID_ANY, label="",
               pos=(0, 70), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[4], id=wx.ID_ANY, label="",
+              parent=runeBoxList[4], id=wx.ID_ANY, label="",
               pos=(0, 80), size=(105, 10)
             )
           ],
           [
             wx.StaticText(
-              parent=runeListBox[5], id=wx.ID_ANY, label="",
+              parent=runeBoxList[5], id=wx.ID_ANY, label="",
               pos=(0, 50), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[5], id=wx.ID_ANY, label="",
+              parent=runeBoxList[5], id=wx.ID_ANY, label="",
               pos=(0, 60), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[5], id=wx.ID_ANY, label="",
+              parent=runeBoxList[5], id=wx.ID_ANY, label="",
               pos=(0, 70), size=(105, 10)
             ),
             wx.StaticText(
-              parent=runeListBox[5], id=wx.ID_ANY, label="",
+              parent=runeBoxList[5], id=wx.ID_ANY, label="",
               pos=(0, 80), size=(105, 10)
             )
           ]
         ]
 
+        optimizeButton = wx.Button(
+          parent=self, id=wx.ID_ANY, pos=(500, 500), size=(105, 30),
+          style=wx.LC_REPORT, label="Optimize"
+        )
+        self.detailsSizer.Add(optimizeButton)
+        self.Bind(wx.EVT_BUTTON, self.goToOptimizer, optimizeButton)
+
+        # By default, hide all optimization options
+        self.detailsSizer.ShowItems(False)
+
 
     def populateUnitList(self, event):
         """Populates the unit list.
@@ -476,7 +505,7 @@ class PanelUnits(wx.Panel):
         """
 
         # Get units from db
-        name = self.filterName.GetValue()
+        name = self.filterNameText.GetValue()
         query = """
           SELECT
             id,
@@ -491,11 +520,11 @@ class PanelUnits(wx.Panel):
           WHERE
             name LIKE '%""" + name + """%'
         """
-        if self.filterStorage.GetValue() == False:
+        if self.filterStorageCheck.GetValue() == False:
             query += " AND storage = 0 "
-        if self.filterNoRunes.GetValue() == False:
+        if self.filterNoRunesCheck.GetValue() == False:
             query += " AND id IN (SELECT DISTINCT unit FROM runes) "
-        if self.filterNoTeams.GetValue() == False:
+        if self.filterNoTeamsCheck.GetValue() == False:
             query += " AND id IN (SELECT DISTINCT unit FROM units_teams) "
         query += " ORDER BY priority DESC; ";
         print(query)
@@ -513,6 +542,18 @@ class PanelUnits(wx.Panel):
                 self.unitList.SetItem(i, 2, " ")
             i = i + 1
 
+    def goToOptimizer(self, event = None):
+        """Prepares the optimizer panel with the selected unit and redirects.
+
+        Parameters
+        ----------
+        event : wxEvent, optional
+            The event that triggered the call (default is None).
+
+        """
+        self.GetParent().frameOptimizer.unitId = self.selectedId
+        self.GetParent().frameOptimizer.selectUnit(event=None)
+        self.GetParent().ChangeSelection(2)
 
     def unitSelected(self, event):
         """Loads a unit info and enables optimizaton options.
@@ -527,9 +568,6 @@ class PanelUnits(wx.Panel):
         """
         id = str(self.unitList.GetItemData(self.unitList.GetFirstSelected()))
 
-        #print("UNIT SELECTED: " + id)
-
-
         cursor = conn.execute("""
           SELECT
             base_hp,
@@ -555,12 +593,10 @@ class PanelUnits(wx.Panel):
             id = """ + id + """;
         """)
         row = cursor.fetchone()
-        #self.unitContent.ShowItems(True)
-        #self.unitNameValue = str(row[17])
-        #self.unitName.SetLabel(str(row[17]) + "    (# " + str(row[16]) + ")")
+        self.selectedId = id
+        self.detailsSizer.ShowItems(True)
         for i in range(0, 8):
             value = str(row[i])
-        #    self.minStatSlid[i].SetMin(int(value))
             if i > 3:
                 value = value + "%"
             else:
@@ -568,9 +604,6 @@ class PanelUnits(wx.Panel):
             self.statGrid.SetCellValue(row=i, col=0, s=value)
         for i in range(0, 8):
             value = str(row[8 + i])
-        #    self.minStatSlid[i].SetValue(int(value))
-        #    self.minStatText[i].SetValue(value)
-        #    self.currentStats[i] = int(value)
             if i > 3:
                 value = value + "%"
             else:
@@ -587,8 +620,6 @@ class PanelUnits(wx.Panel):
           int(self.statGrid.GetCellValue(row=2, col=1).replace("%", ""))
         currentEhp = math.ceil((((currentDef * 3.5) + 1140) * currentHp) / 1000)
         self.statGrid.SetCellValue(row=8, col=1, s=str(currentEhp))
-        #self.minStatSlid[8].SetValue(currentEhp)
-        #self.minStatText[8].SetValue(str(currentEhp))
         baseAtk = int(self.statGrid.GetCellValue(row=1, col=0))
         baseCrr = int(self.statGrid.GetCellValue(row=4, col=0).replace("%", ""))
         baseCrd = int(self.statGrid.GetCellValue(row=5, col=0).replace("%", ""))
@@ -600,22 +631,18 @@ class PanelUnits(wx.Panel):
           ((baseAtk + (baseAtk * baseCrd / 100)) * baseCrr / 100)
         )
         self.statGrid.SetCellValue(row=9, col=0, s=str(baseDmg))
-        #self.minStatSlid[9].SetMin(baseDmg)
         currentAtk = int(self.statGrid.GetCellValue(row=1, col=1))
         currentCrr = \
           int(self.statGrid.GetCellValue(row=4, col=0).replace("%", ""))
         currentCrd = \
           int(self.statGrid.GetCellValue(row=5, col=1).replace("%", ""))
         if (currentCrr > 100):
-            # Dont use crit rate over 100
             currentCrr = 100
         currentDmg = math.ceil(
           (currentAtk * (100 - currentCrr) / 100) +
           ((currentAtk + (currentAtk * currentCrd / 100)) * currentCrr / 100)
         )
         self.statGrid.SetCellValue(row=9, col=1, s=str(currentDmg))
-        #self.minStatSlid[9].SetValue(currentDmg)
-        #self.minStatText[9].SetValue(str(currentDmg))
 
         # Populate the runes
         cursor = conn.execute("""
@@ -635,9 +662,9 @@ class PanelUnits(wx.Panel):
         i = 0
         for row in cursor:
             # Rows are 19 charactes width
-            self.runeSets[i].SetLabel(set_names[row[2]])
+            self.setLabelList[i].SetLabel(set_names[row[2]])
             rid = ("#" + str(row[0])).rjust(13, " ")
-            self.runeIds[i].SetLabel(rid)
+            self.idLabelList[i].SetLabel(rid)
             #setname = set_names[row[2]][0:6].ljust(6, " ")
 
             level = "+" + str(row[3]).ljust(2, " ")
@@ -681,10 +708,10 @@ class PanelUnits(wx.Panel):
                         value = value + "%"
                 line = name + value
                 if slot == -1: # main
-                    self.runeMains[i].SetLabel(line + "|   " + level)
+                    self.mainLabelList[i].SetLabel(line + "|   " + level)
                 elif slot == 0: # innate
                     innateLabel = line
                 else: # normal stats
-                    self.runeStats[i][slot - 1].SetLabel(line)
-            self.runeInnates[i].SetLabel(innateLabel + "|" + eff)
+                    self.statLabelList[i][slot - 1].SetLabel(line)
+            self.innateLabelList[i].SetLabel(innateLabel + "|" + eff)
             i = i + 1

+ 0 - 721
src/RuneOptimizerGUI/classes/ResultsFrame.py

@@ -1,721 +0,0 @@
-"""
-This file is part of RuneOptimizer.
-
-RuneOptimizer is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-more details.
-
-You should have received a copy of the GNU General Public License along with
-RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
-
-"""
-
-
-class ResultsFrame(wx.Frame):
-    """
-    The frame uset to see and check results.
-
-    Parameters
-    ----------
-    unitId : str
-        ID of the unit being optimized (default "").
-    unitName : str
-        Name of the unit being optimized (default "").
-    data : Python Object
-        Results from RuneOptimizer (default None).
-    currentStats : int[10]
-        The current stats of the unit being optimized. (default is
-        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).
-    page : int
-        Currently displayed page, 0-index (default 0).
-    totalPages : int
-        Number of pages of results (default 0).
-    linesPerPage : int
-        Number of results to show per page (default 10).
-    pgPrevBt : wx.Button
-        Button to go to the previous page.
-    pgPrevBt : wx.Button
-        Button to go to the previous page.
-    resultsPageIndicator : wx.StaticText
-        Label to indicate the current and maximum pages.
-    resultGrid : wx.Grid.grid
-        Table of results.
-    resultContent : wx.BoxSizer
-        Holds every widget that is hidden until a result is selected.
-    statGrid : wx.Grid.grid
-        Table to show the new stats with the selected result.
-    runeIds : wx.StaticText[6]
-        Labels with the IDs of the runes in the current result.
-    runeLocations : wx.StaticText[6]
-        Labels with the locations of the runes in the current result.
-    runeSets : wx.StaticText[6]
-        Labels with the set names of the runes in the current result.
-    runeMains : wx.StaticText[6]
-        Labels with the main stats of the runes in the current result.
-    runeInnates : wx.StaticText[6]
-        Labels with the innates of the runes in the current result.
-    runeStats : wx.StaticText[6][4]
-        Labels with the stats of the runes in the current result.
-    selectedResultndex : int
-        Selected result index (default -1).
-
-    Methods
-    -------
-    processResults(jsonData)
-        Processes data obtained from RuneOptimizer.
-    pgPrev(event)
-        Goes to the previous result page.
-    pgNext(event)
-        Goes to the next result page.
-    closeWindow(event)
-        Closes the frame.
-    applyRunes(event)
-        Applies the runes in the currently selected result.
-    printResults()
-        Populates the results table with the results in the currently
-        selected page.
-    resultSelected(event)
-        Populates and shows the runes and effective stats with the
-        currently seleced result.
-
-    """
-
-    unitId = ""
-    unitName = ""
-    data = None
-    currentStats = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
-    page = 0
-    totalPages = 0
-    linesPerPage = 10
-    pgPrevBt = None
-    pgNextBt = None
-    resultsPageIndicator = None
-    resultGrid = None
-    resultContent = None
-    statGrid = None
-    runeIds = None
-    runeLocations = None
-    runeSets = None
-    runeMains = None
-    runeInnates = None
-    runeStats = None
-    selectedResultIndex = -1
-
-    def __init__(self, *args, **kw):
-        """Initializes the class.
-
-        Sets upt all the widgets.
-
-        """
-
-        global conn
-        # ensure the parent's __init__ is called
-        super(ResultsFrame, self).__init__(*args, **kw)
-
-        # create a panel in the frame
-        pnl = wx.Panel(self)
-
-        self.resultGrid = wx.grid.Grid(parent=pnl, id=-1, pos=(50, 30), size=(544, 220))
-        self.resultGrid.CreateGrid(numRows=10, numCols=11, selmode=wx.grid.Grid.GridSelectionModes.SelectRows)
-        self.resultGrid.EnableEditing(False)
-        self.resultGrid.SetDefaultCellAlignment(horiz=wx.ALIGN_RIGHT, vert=wx.ALIGN_CENTRE)
-        monospaceFont = wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
-        self.resultGrid.SetDefaultCellFont(monospaceFont)
-        self.resultGrid.SetRowLabelSize(width=35)
-        self.resultGrid.SetColLabelValue(col=0, value="Rating")
-        self.resultGrid.SetColSize(col=0, width=50)
-        self.resultGrid.SetColLabelValue(col=1, value="HP")
-        self.resultGrid.SetColSize(col=1, width=50)
-        self.resultGrid.SetColLabelValue(col=2, value="ATK")
-        self.resultGrid.SetColSize(col=2, width=40)
-        self.resultGrid.SetColLabelValue(col=3, value="DEF")
-        self.resultGrid.SetColSize(col=3, width=40)
-        self.resultGrid.SetColLabelValue(col=4, value="SPD")
-        self.resultGrid.SetColSize(col=4, width=40)
-        self.resultGrid.SetColLabelValue(col=5, value="CRR")
-        self.resultGrid.SetColSize(col=5, width=40)
-        self.resultGrid.SetColLabelValue(col=6, value="CRD")
-        self.resultGrid.SetColSize(col=6, width=40)
-        self.resultGrid.SetColLabelValue(col=7, value="RES")
-        self.resultGrid.SetColSize(col=7, width=40)
-        self.resultGrid.SetColLabelValue(col=8, value="ACC")
-        self.resultGrid.SetColSize(col=8, width=40)
-        self.resultGrid.SetColLabelValue(col=9, value="EHP")
-        self.resultGrid.SetColSize(col=9, width=60)
-        self.resultGrid.SetColLabelValue(col=10, value="DMG")
-        self.resultGrid.SetColSize(col=10, width=50)
-        self.resultGrid.SetColLabelSize(height=20)
-        self.resultGrid.SetDefaultRowSize(height=20)
-        self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.resultSelected, self.resultGrid)
-
-        # Paginator
-        self.pgPrevBt = wx.Button(parent=pnl, id=-1, pos=(580, 30), size=(40, 50), style=wx.LC_REPORT, label="Prev\npage")
-        self.resultsPageIndicator = wx.StaticText(parent=pnl, label="1/1",id=-1, pos=(580, 80), size=(40, 15), style=wx.ALIGN_CENTRE_HORIZONTAL)
-        self.pgNextBt = wx.Button(parent=pnl, id=-1, pos=(580, 100), size=(40, 50), style=wx.LC_REPORT, label="Next\npage")
-        self.Bind(wx.EVT_BUTTON, self.pgPrev, self.pgPrevBt)
-        self.Bind(wx.EVT_BUTTON, self.pgNext, self.pgNextBt)
-
-        self.resultContent = wx.BoxSizer(wx.VERTICAL)
-
-        # Stats table
-        self.statGrid = wx.grid.Grid(parent=pnl, id=-1, pos=(650, 30), size=(205, 220), style=wx.LC_REPORT)
-        self.statGrid.CreateGrid(numRows=10, numCols=2, selmode=wx.grid.Grid.GridSelectionModes.SelectRowsOrColumns)
-        self.statGrid.EnableEditing(False)
-        self.statGrid.SetDefaultCellAlignment(horiz=wx.ALIGN_RIGHT, vert=wx.ALIGN_CENTRE)
-        monospaceFont = wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
-        self.statGrid.SetDefaultCellFont(monospaceFont)
-        self.statGrid.SetColSize(col=0, width=70)
-        self.statGrid.SetColLabelValue(col=0, value="Value")
-        self.statGrid.SetColLabelValue(col=1, value="Diff")
-        self.statGrid.SetRowLabelSize(width=35)
-        self.statGrid.SetColLabelSize(height=20)
-        self.statGrid.SetRowSize(row=0, height=20)
-        self.statGrid.SetRowSize(row=1, height=20)
-        self.statGrid.SetRowSize(row=2, height=20)
-        self.statGrid.SetRowSize(row=3, height=20)
-        self.statGrid.SetRowSize(row=4, height=20)
-        self.statGrid.SetRowSize(row=5, height=20)
-        self.statGrid.SetRowSize(row=6, height=20)
-        self.statGrid.SetRowSize(row=7, height=20)
-        self.statGrid.SetRowSize(row=8, height=20)
-        self.statGrid.SetRowSize(row=9, height=20)
-        self.statGrid.SetRowLabelValue(row=0, value=" HP")
-        self.statGrid.SetRowLabelValue(row=1, value="ATK")
-        self.statGrid.SetRowLabelValue(row=2, value="DEF")
-        self.statGrid.SetRowLabelValue(row=3, value="SPD")
-        self.statGrid.SetRowLabelValue(row=4, value="CRR")
-        self.statGrid.SetRowLabelValue(row=5, value="CRD")
-        self.statGrid.SetRowLabelValue(row=6, value="RES")
-        self.statGrid.SetRowLabelValue(row=7, value="ACC")
-        self.statGrid.SetRowLabelValue(row=8, value="EHP")
-        self.statGrid.SetRowLabelValue(row=9, value="DMG")
-        self.resultContent.Add(self.statGrid)
-
-        monospaceFont = wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
-        monospaceFont.PointSize -= 2
-        monospaceFontBold = wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
-        monospaceFontBold.PointSize -= 2
-        monospaceFontItalic = wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_ITALIC, wx.FONTWEIGHT_NORMAL)
-        monospaceFontItalic.PointSize -= 2
-
-        #Rune set list
-        runeListBox = [
-          wx.StaticBox(parent=pnl, label="Slot1:",id=-1, pos=(200, 255), size=(140, 160)),
-          wx.StaticBox(parent=pnl, label="Slot2:",id=-1, pos=(350, 255), size=(140, 160)),
-          wx.StaticBox(parent=pnl, label="Slot3:",id=-1, pos=(350, 420), size=(140, 160)),
-          wx.StaticBox(parent=pnl, label="Slot4:",id=-1, pos=(200, 420), size=(140, 160)),
-          wx.StaticBox(parent=pnl, label="Slot5:",id=-1, pos=(50, 420), size=(140, 160)),
-          wx.StaticBox(parent=pnl, label="Slot6:",id=-1, pos=(50, 255), size=(140, 160)),
-        ]
-        for i in range(0, 6):
-            runeListBox[i].SetFont(monospaceFont)
-            self.resultContent.Add(runeListBox[i])
-
-        self.runeIds = [
-          wx.StaticText(runeListBox[0], label="",id=-1, pos=(5, 0), size=(120, 10)),
-          wx.StaticText(runeListBox[1], label="",id=-1, pos=(5, 0), size=(120, 10)),
-          wx.StaticText(runeListBox[2], label="",id=-1, pos=(5, 0), size=(120, 10)),
-          wx.StaticText(runeListBox[3], label="",id=-1, pos=(5, 0), size=(120, 10)),
-          wx.StaticText(runeListBox[4], label="",id=-1, pos=(5, 0), size=(120, 10)),
-          wx.StaticText(runeListBox[5], label="",id=-1, pos=(5, 0), size=(120, 10)),
-        ]
-
-        self.runeLocations = [
-          wx.StaticText(runeListBox[0], label="",id=-1, pos=(5, 15), size=(120, 10)),
-          wx.StaticText(runeListBox[1], label="",id=-1, pos=(5, 15), size=(120, 10)),
-          wx.StaticText(runeListBox[2], label="",id=-1, pos=(5, 15), size=(120, 10)),
-          wx.StaticText(runeListBox[3], label="",id=-1, pos=(5, 15), size=(120, 10)),
-          wx.StaticText(runeListBox[4], label="",id=-1, pos=(5, 15), size=(120, 10)),
-          wx.StaticText(runeListBox[5], label="",id=-1, pos=(5, 15), size=(120, 10)),
-        ]
-
-        self.runeSets = [
-          wx.StaticText(runeListBox[0], label="",id=-1, pos=(5, 30), size=(120, 10)),
-          wx.StaticText(runeListBox[1], label="",id=-1, pos=(5, 30), size=(120, 10)),
-          wx.StaticText(runeListBox[2], label="",id=-1, pos=(5, 30), size=(120, 10)),
-          wx.StaticText(runeListBox[3], label="",id=-1, pos=(5, 30), size=(120, 10)),
-          wx.StaticText(runeListBox[4], label="",id=-1, pos=(5, 30), size=(120, 10)),
-          wx.StaticText(runeListBox[5], label="",id=-1, pos=(5, 30), size=(120, 10)),
-        ]
-
-        wx.StaticLine(parent=runeListBox[0], id=-1, pos=(5, 45), size=(130, 1), style=wx.LC_REPORT)
-        wx.StaticLine(parent=runeListBox[1], id=-1, pos=(5, 45), size=(130, 1), style=wx.LC_REPORT)
-        wx.StaticLine(parent=runeListBox[2], id=-1, pos=(5, 45), size=(130, 1), style=wx.LC_REPORT)
-        wx.StaticLine(parent=runeListBox[3], id=-1, pos=(5, 45), size=(130, 1), style=wx.LC_REPORT)
-        wx.StaticLine(parent=runeListBox[4], id=-1, pos=(5, 45), size=(130, 1), style=wx.LC_REPORT)
-        wx.StaticLine(parent=runeListBox[5], id=-1, pos=(5, 45), size=(130, 1), style=wx.LC_REPORT)
-
-        self.runeMains = [
-          wx.StaticText(runeListBox[0], label="",id=-1, pos=(5, 50), size=(120, 10)),
-          wx.StaticText(runeListBox[1], label="",id=-1, pos=(5, 50), size=(120, 10)),
-          wx.StaticText(runeListBox[2], label="",id=-1, pos=(5, 50), size=(120, 10)),
-          wx.StaticText(runeListBox[3], label="",id=-1, pos=(5, 50), size=(120, 10)),
-          wx.StaticText(runeListBox[4], label="",id=-1, pos=(5, 50), size=(120, 10)),
-          wx.StaticText(runeListBox[5], label="",id=-1, pos=(5, 50), size=(120, 10)),
-        ]
-        for i in range(0, 6):
-            self.runeMains[i].SetFont(monospaceFontBold)
-
-        self.runeInnates = [
-          wx.StaticText(runeListBox[0], label="",id=-1, pos=(5, 65), size=(120, 10)),
-          wx.StaticText(runeListBox[1], label="",id=-1, pos=(5, 65), size=(120, 10)),
-          wx.StaticText(runeListBox[2], label="",id=-1, pos=(5, 65), size=(120, 10)),
-          wx.StaticText(runeListBox[3], label="",id=-1, pos=(5, 65), size=(120, 10)),
-          wx.StaticText(runeListBox[4], label="",id=-1, pos=(5, 65), size=(120, 10)),
-          wx.StaticText(runeListBox[5], label="",id=-1, pos=(5, 65), size=(120, 10)),
-        ]
-        for i in range(0, 6):
-            self.runeInnates[i].SetFont(monospaceFontItalic)
-
-        self.runeStats = [
-          [
-            wx.StaticText(runeListBox[0], label="",id=-1, pos=(5, 80), size=(120, 10)),
-            wx.StaticText(runeListBox[0], label="",id=-1, pos=(5, 95), size=(120, 10)),
-            wx.StaticText(runeListBox[0], label="",id=-1, pos=(5, 110), size=(120, 10)),
-            wx.StaticText(runeListBox[0], label="",id=-1, pos=(5, 125), size=(120, 10))
-          ],
-          [
-            wx.StaticText(runeListBox[1], label="",id=-1, pos=(5, 80), size=(120, 10)),
-            wx.StaticText(runeListBox[1], label="",id=-1, pos=(5, 95), size=(120, 10)),
-            wx.StaticText(runeListBox[1], label="",id=-1, pos=(5, 110), size=(120, 10)),
-            wx.StaticText(runeListBox[1], label="",id=-1, pos=(5, 125), size=(120, 10))
-          ],
-          [
-            wx.StaticText(runeListBox[2], label="",id=-1, pos=(5, 80), size=(120, 10)),
-            wx.StaticText(runeListBox[2], label="",id=-1, pos=(5, 95), size=(120, 10)),
-            wx.StaticText(runeListBox[2], label="",id=-1, pos=(5, 110), size=(120, 10)),
-            wx.StaticText(runeListBox[2], label="",id=-1, pos=(5, 125), size=(120, 10))
-          ],
-          [
-            wx.StaticText(runeListBox[3], label="",id=-1, pos=(5, 80), size=(120, 10)),
-            wx.StaticText(runeListBox[3], label="",id=-1, pos=(5, 95), size=(120, 10)),
-            wx.StaticText(runeListBox[3], label="",id=-1, pos=(5, 110), size=(120, 10)),
-            wx.StaticText(runeListBox[3], label="",id=-1, pos=(5, 125), size=(120, 10))
-          ],
-          [
-            wx.StaticText(runeListBox[4], label="",id=-1, pos=(5, 80), size=(120, 10)),
-            wx.StaticText(runeListBox[4], label="",id=-1, pos=(5, 95), size=(120, 10)),
-            wx.StaticText(runeListBox[4], label="",id=-1, pos=(5, 110), size=(120, 10)),
-            wx.StaticText(runeListBox[4], label="",id=-1, pos=(5, 125), size=(120, 10))
-          ],
-          [
-            wx.StaticText(runeListBox[5], label="",id=-1, pos=(5, 80), size=(120, 10)),
-            wx.StaticText(runeListBox[5], label="",id=-1, pos=(5, 95), size=(120, 10)),
-            wx.StaticText(runeListBox[5], label="",id=-1, pos=(5, 110), size=(120, 10)),
-            wx.StaticText(runeListBox[5], label="",id=-1, pos=(5, 125), size=(120, 10))
-          ],
-        ]
-
-        # Action buttons
-        applyBt = wx.Button(parent=pnl, id=-1, pos=(650, 330), size=(165, 60), style=wx.LC_REPORT, label="Apply runes")
-        self.Bind(wx.EVT_BUTTON, self.applyRunes, applyBt)
-        self.resultContent.Add(applyBt)
-        closeBt = wx.Button(parent=pnl, id=-1, pos=(650, 430), size=(165, 60), style=wx.LC_REPORT, label="Close")
-        self.Bind(wx.EVT_BUTTON, self.closeWindow, closeBt)
-
-        # By default, hide everything
-        self.resultContent.ShowItems(False)
-
-    def processResults(self, jsonData):
-        """Processes data obtained from RuneOptimizer.
-
-        Reads the JSON data and initializes the property data.
-        Automatically calls printResults();
-
-        Parameters
-        ----------
-        jsonData : str
-            The data, as received from RuneOptimizer.
-
-        """
-
-        self.data = json.loads(jsonData, object_hook=lambda d: SimpleNamespace(**d))
-        self.totalPages = math.ceil(len(self.data.results) / self.linesPerPage)
-        self.printResults()
-
-    def pgPrev(self, event):
-        """Goes to the previous page of results.
-
-        Checks if there is a previous page to go to. If so, it
-        automatically calls printResults();
-
-        Parameters
-        ----------
-        event : wxEvent, optional
-            The event that triggered the call (default is None).
-
-        """
-
-        if self.page > 0:
-            self.page -= 1
-            self.printResults()
-
-    def pgNext(self, event):
-        """Goes to the next page of results.
-
-        Checks if there is a next page to go to. If so, it
-        automatically calls printResults();
-
-        Parameters
-        ----------
-        event : wxEvent, optional
-            The event that triggered the call (default is None).
-
-        """
-
-        if self.page < self.totalPages:
-            self.page += 1
-            self.printResults()
-
-    def closeWindow(self, event):
-        """Closes the window.
-
-        Parameters
-        ----------
-        event : wxEvent, optional
-            The event that triggered the call (default is None).
-
-        """
-
-        self.Close(True)
-
-    def applyRunes(self, event):
-        """Applies the selected results and saves data to the database.
-
-        Parameters
-        ----------
-        event : wxEvent, optional
-            The event that triggered the call (default is None).
-
-        """
-
-        global conn
-
-        if (self.selectedResultIndex < 0):
-            # TODO: Show error
-            return;
-        print("self.selectedResultIndex: " + str(self.selectedResultIndex))
-        for i in range(0, 6):
-            print(self.data.results[self.selectedResultIndex].runes[i])
-        # First, unassign all runes currently assigned to the unit
-        cursor = conn.execute(
-          """
-            UPDATE runes SET unit = null
-            WHERE unit = ?
-          """,
-          (
-            self.unitId,
-          )
-        )
-
-        # Next, mark units as modified
-        cursor = conn.execute(
-          """
-            UPDATE units SET modified = 1
-            WHERE id = ? OR id IN (SELECT unit FROM runes WHERE id IN (?, ?, ?, ?, ?, ?))
-          """,
-          (
-            self.unitId,
-            self.data.results[self.selectedResultIndex].runes[0],
-            self.data.results[self.selectedResultIndex].runes[1],
-            self.data.results[self.selectedResultIndex].runes[2],
-            self.data.results[self.selectedResultIndex].runes[3],
-            self.data.results[self.selectedResultIndex].runes[4],
-            self.data.results[self.selectedResultIndex].runes[5]
-          )
-        )
-
-        # Lastly, assign the runes
-        cursor = conn.execute(
-          """
-            UPDATE runes SET unit = ?
-            WHERE id IN (?, ?, ?, ?, ?, ?)
-          """,
-          (
-            self.unitId,
-            self.data.results[self.selectedResultIndex].runes[0],
-            self.data.results[self.selectedResultIndex].runes[1],
-            self.data.results[self.selectedResultIndex].runes[2],
-            self.data.results[self.selectedResultIndex].runes[3],
-            self.data.results[self.selectedResultIndex].runes[4],
-            self.data.results[self.selectedResultIndex].runes[5]
-          )
-        )
-        conn.commit()
-        # TODO: Recalculate all modified units stats from the database
-        print("Applied!")
-        recalculteStatsOfModifiedUnits()
-        print("All recalculated!")
-
-        # Fetch the new values for self.currentStats
-        cursor = conn.execute(
-          """
-            SELECT
-              current_hp,
-              current_atk,
-              current_def,
-              current_spd,
-              current_crr,
-              current_crd,
-              current_res,
-              current_acc
-            FROM units
-            WHERE id = ?
-          """,
-          (
-            self.unitId,
-          )
-        )
-        row = cursor.fetchone()
-        for i in range(0, 8):
-            self.currentStats[i] = int(row[i])
-        self.currentStats[9] = math.ceil((((self.currentStats[2] * 3.5) + 1140) * self.currentStats[0]) / 1000)
-        self.currentStats[10] = math.ceil((self.currentStats[1] * (100 - self.currentStats[4]) / 100) + ((self.currentStats[1] + (self.currentStats[1] * self.currentStats[5] / 100)) * self.currentStats[4] / 100));
-        self.resultSelected(None)
-
-    def printResults(self):
-        """Populates the results table with the results in the
-        currently selected page.
-
-        It doesn't change the selcted result. Automaticcaly called
-        after changing pages or processing data.
-        """
-
-        self.pgPrevBt.Enable(True)
-        self.pgNextBt.Enable(True)
-        if self.totalPages == 1:
-            self.pgPrevBt.Enable(False)
-            self.pgNextBt.Enable(False)
-        elif self.page == 0:
-            self.pgPrevBt.Enable(False)
-        elif self.page + 1 == self.totalPages:
-            self.pgNextBt.Enable(False)
-        self.resultsPageIndicator.SetLabel(str(self.page + 1) + "/" + str(self.totalPages))
-        #for result in self.data.results:
-        for i in range(0, 10):
-            rindex = i + (self.linesPerPage * self.page)
-            if (len(self.data.results) > rindex):
-                self.resultGrid.SetRowLabelValue(row=i, value=str(rindex + 1))
-                result = self.data.results[rindex]
-                self.resultGrid.SetCellValue(row=i, col=0, s=str(result.rating))
-                self.resultGrid.SetCellValue(row=i, col=1, s=str(result.hp))
-                self.resultGrid.SetCellValue(row=i, col=2, s=str(result.atk))
-                self.resultGrid.SetCellValue(row=i, col=3, s=str(result.dfc))
-                self.resultGrid.SetCellValue(row=i, col=4, s=str(result.spd))
-                self.resultGrid.SetCellValue(row=i, col=5, s=str(result.crr))
-                self.resultGrid.SetCellValue(row=i, col=6, s=str(result.crd))
-                self.resultGrid.SetCellValue(row=i, col=7, s=str(result.res))
-                self.resultGrid.SetCellValue(row=i, col=8, s=str(result.acc))
-                self.resultGrid.SetCellValue(row=i, col=9, s=str(result.ehp))
-                self.resultGrid.SetCellValue(row=i, col=10, s=str(result.dmg))
-            else:
-                self.resultGrid.SetRowLabelValue(row=i, value="")
-                for j in range(0, 11):
-                    self.resultGrid.SetCellValue(row=i, col=j, s="")
-
-    def resultSelected(self, event):
-        """Populates and shows the runes and effective stats with the
-        currently seleced result.
-
-        It also enables the apply button.
-
-        Parameters
-        ----------
-        event : wxEvent, optional
-            The event that triggered the call (default is None).
-
-        """
-
-        selectedLine = self.resultGrid.GetSelectedRows()[0]
-        self.selectedResultIndex = selectedLine + (self.linesPerPage * self.page)
-        self.statGrid.SetCellValue(row=0, col=0, s=str(self.data.results[self.selectedResultIndex].hp) + " ")
-        diff = self.data.results[self.selectedResultIndex].hp - self.currentStats[0]
-        if (diff < 0):
-            self.statGrid.SetCellValue(row=0, col=1, s="- " + str(abs(diff)) + " ")
-            self.statGrid.SetCellTextColour(row=0, col=1, colour=wx.Colour(red=255, green=0, blue=0))
-        elif (diff > 0):
-            self.statGrid.SetCellValue(row=0, col=1, s="+ " + str(diff) + " ")
-            self.statGrid.SetCellTextColour(row=0, col=1, colour=wx.Colour(red=0, green=255, blue=0))
-        else:
-            self.statGrid.SetCellValue(row=0, col=1, s="")
-
-        self.statGrid.SetCellValue(row=1, col=0, s=str(self.data.results[self.selectedResultIndex].atk) + " ")
-        diff = self.data.results[self.selectedResultIndex].atk - self.currentStats[1]
-        if (diff < 0):
-            self.statGrid.SetCellValue(row=1, col=1, s="- " + str(abs(diff)) + " ")
-            self.statGrid.SetCellTextColour(row=1, col=1, colour=wx.Colour(red=255, green=0, blue=0))
-        elif (diff > 0):
-            self.statGrid.SetCellValue(row=1, col=1, s="+ " + str(diff) + " ")
-            self.statGrid.SetCellTextColour(row=1, col=1, colour=wx.Colour(red=0, green=255, blue=0))
-        else:
-            self.statGrid.SetCellValue(row=1, col=1, s="")
-
-        self.statGrid.SetCellValue(row=2, col=0, s=str(self.data.results[self.selectedResultIndex].dfc) + " ")
-        diff = self.data.results[self.selectedResultIndex].atk - self.currentStats[2]
-        if (diff < 0):
-            self.statGrid.SetCellValue(row=2, col=1, s="- " + str(abs(diff)) + " ")
-            self.statGrid.SetCellTextColour(row=1, col=1, colour=wx.Colour(red=255, green=0, blue=0))
-        elif (diff > 0):
-            self.statGrid.SetCellValue(row=2, col=1, s="+ " + str(diff) + " ")
-            self.statGrid.SetCellTextColour(row=2, col=1, colour=wx.Colour(red=0, green=255, blue=0))
-        else:
-            self.statGrid.SetCellValue(row=2, col=1, s="")
-
-        self.statGrid.SetCellValue(row=3, col=0, s=str(self.data.results[self.selectedResultIndex].spd) + " ")
-        diff = self.data.results[self.selectedResultIndex].spd - self.currentStats[3]
-        if (diff < 0):
-            self.statGrid.SetCellValue(row=3, col=1, s="- " + str(abs(diff)) + " ")
-            self.statGrid.SetCellTextColour(row=3, col=1, colour=wx.Colour(red=255, green=0, blue=0))
-        elif (diff > 0):
-            self.statGrid.SetCellValue(row=3, col=1, s="+ " + str(diff) + " ")
-            self.statGrid.SetCellTextColour(row=3, col=1, colour=wx.Colour(red=0, green=255, blue=0))
-        else:
-            self.statGrid.SetCellValue(row=3, col=1, s="")
-
-
-        self.statGrid.SetCellValue(row=4, col=0, s=str(self.data.results[self.selectedResultIndex].crr) + "%")
-        diff = self.data.results[self.selectedResultIndex].crr - self.currentStats[4]
-        if (diff < 0):
-            self.statGrid.SetCellValue(row=4, col=1, s="- " + str(abs(diff)) + "%")
-            self.statGrid.SetCellTextColour(row=4, col=1, colour=wx.Colour(red=255, green=0, blue=0))
-        elif (diff > 0):
-            self.statGrid.SetCellValue(row=4, col=1, s="+ " + str(diff) + "%")
-            self.statGrid.SetCellTextColour(row=4, col=1, colour=wx.Colour(red=0, green=255, blue=0))
-        else:
-            self.statGrid.SetCellValue(row=4, col=1, s="")
-
-        self.statGrid.SetCellValue(row=5, col=0, s=str(self.data.results[self.selectedResultIndex].crd) + "%")
-        diff = self.data.results[self.selectedResultIndex].crd - self.currentStats[5]
-        if (diff < 0):
-            self.statGrid.SetCellValue(row=5, col=1, s="- " + str(abs(diff)) + "%")
-            self.statGrid.SetCellTextColour(row=5, col=1, colour=wx.Colour(red=255, green=0, blue=0))
-        elif (diff > 0):
-            self.statGrid.SetCellValue(row=5, col=1, s="+ " + str(diff) + "%")
-            self.statGrid.SetCellTextColour(row=5, col=1, colour=wx.Colour(red=0, green=255, blue=0))
-        else:
-            self.statGrid.SetCellValue(row=5, col=1, s="")
-
-        self.statGrid.SetCellValue(row=6, col=0, s=str(self.data.results[self.selectedResultIndex].res) + "%")
-        diff = self.data.results[self.selectedResultIndex].res - self.currentStats[6]
-        if (diff < 0):
-            self.statGrid.SetCellValue(row=6, col=1, s="- " + str(abs(diff)) + "%")
-            self.statGrid.SetCellTextColour(row=6, col=1, colour=wx.Colour(red=255, green=0, blue=0))
-        elif (diff > 0):
-            self.statGrid.SetCellValue(row=6, col=1, s="+ " + str(diff) + "%")
-            self.statGrid.SetCellTextColour(row=6, col=1, colour=wx.Colour(red=0, green=255, blue=0))
-        else:
-            self.statGrid.SetCellValue(row=6, col=1, s="")
-
-        self.statGrid.SetCellValue(row=7, col=0, s=str(self.data.results[self.selectedResultIndex].acc) + "%")
-        diff = self.data.results[self.selectedResultIndex].acc - self.currentStats[7]
-        if (diff < 0):
-            self.statGrid.SetCellValue(row=7, col=1, s="- " + str(abs(diff)) + "%")
-            self.statGrid.SetCellTextColour(row=7, col=1, colour=wx.Colour(red=255, green=0, blue=0))
-        elif (diff > 0):
-            self.statGrid.SetCellValue(row=7, col=1, s="+ " + str(diff) + "%")
-            self.statGrid.SetCellTextColour(row=7, col=1, colour=wx.Colour(red=0, green=255, blue=0))
-        else:
-            self.statGrid.SetCellValue(row=7, col=1, s="")
-
-        self.statGrid.SetCellValue(row=8, col=0, s=str(self.data.results[self.selectedResultIndex].ehp) + " ")
-        diff = self.data.results[self.selectedResultIndex].ehp - self.currentStats[8]
-        if (diff < 0):
-            self.statGrid.SetCellValue(row=8, col=1, s="- " + str(abs(diff)) + " ")
-            self.statGrid.SetCellTextColour(row=8, col=1, colour=wx.Colour(red=255, green=0, blue=0))
-        elif (diff > 0):
-            self.statGrid.SetCellValue(row=8, col=1, s="+ " + str(diff) + " ")
-            self.statGrid.SetCellTextColour(row=8, col=1, colour=wx.Colour(red=0, green=255, blue=0))
-        else:
-            self.statGrid.SetCellValue(row=8, col=1, s="")
-
-        self.statGrid.SetCellValue(row=9, col=0, s=str(self.data.results[self.selectedResultIndex].dmg) + " ")
-        diff = self.data.results[self.selectedResultIndex].dmg - self.currentStats[9]
-        if (diff < 0):
-            self.statGrid.SetCellValue(row=9, col=1, s="- " + str(abs(diff)) + " ")
-            self.statGrid.SetCellTextColour(row=9, col=1, colour=wx.Colour(red=255, green=0, blue=0))
-        elif (diff > 0):
-            self.statGrid.SetCellValue(row=9, col=1, s="+ " + str(diff) + " ")
-            self.statGrid.SetCellTextColour(row=9, col=1, colour=wx.Colour(red=0, green=255, blue=0))
-        else:
-            self.statGrid.SetCellValue(row=9, col=1, s="")
-
-        self.resultContent.ShowItems(True)
-
-        # Clean the runes
-        for i in range(0, 5):
-            self.runeIds[i].SetLabel("")
-            self.runeLocations[i].SetLabel("")
-            self.runeSets[i].SetLabel("")
-            self.runeMains[i].SetLabel("")
-            self.runeInnates[i].SetLabel("")
-            for j in range(0, 3):
-                self.runeStats[i][j].SetLabel("")
-
-        # Display the runes
-        cursor = conn.execute(
-          """
-            SELECT runes.id, runes.slot, runes.type, runes.level, units.id, units.name
-            FROM runes LEFT JOIN units ON runes.unit = units.id
-            WHERE runes.id IN (?, ?, ?, ?, ?, ?)
-            ORDER BY runes.slot;
-          """,
-          (
-            self.data.results[self.selectedResultIndex].runes[0],
-            self.data.results[self.selectedResultIndex].runes[1],
-            self.data.results[self.selectedResultIndex].runes[2],
-            self.data.results[self.selectedResultIndex].runes[3],
-            self.data.results[self.selectedResultIndex].runes[4],
-            self.data.results[self.selectedResultIndex].runes[5]
-          )
-        )
-        i = 0
-        for row in cursor:
-            # Rows are 21 charactes width
-            self.runeIds[i].SetLabel(("#" + str(row[0])).rjust(21, " "))
-            if row[4] == None:
-                self.runeLocations[i].SetLabel("Storage")
-            else:
-                self.runeLocations[i].SetLabel(str(row[5])[0:9].ljust(9, " ") + " #" + str(row[4]) + "")
-            self.runeSets[i].SetLabel(set_names[row[2]].ljust(18, " ") + "+" + str(row[3]))
-            #print(self.data.results[self.selectedResultIndex].runes[i])
-            cursorStats = conn.execute(
-              """
-                SELECT
-                  slot, stat, value, grind, enchant
-                FROM rune_stats
-                WHERE
-                  rune = ?
-                ORDER BY slot;
-              """,
-              (self.data.results[self.selectedResultIndex].runes[i],)
-            )
-            for rowStats in cursorStats:
-                slot = rowStats[0]
-                if rowStats[4] == 1: # if enchanted
-                    name = (stat_names[rowStats[1]].replace("%", "").replace(" ", "") + " * ").rjust(8, " ")
-                else:
-                    name = (stat_names[rowStats[1]].replace("%", "").replace(" ", "") + "   ").rjust(8, " ")
-                value = str(rowStats[2])
-                if rowStats[1] in [2, 4, 6, 9, 10, 11, 23]:
-                    value = value + "%"
-                else:
-                    value = value + " "
-                value = value.rjust(5)
-                if rowStats[3] > 0: # if grinded
-                    value = value + "  + " + str(rowStats[3])
-                    if rowStats[1] in [2, 4, 6, 9, 10, 11, 23]:
-                        value = value + "%"
-                line = name + value
-                if slot == -1: # main
-                    self.runeMains[i].SetLabel(line)
-                elif slot == 0: # innate
-                    self.runeInnates[i].SetLabel(line)
-                else: # normal stats
-                    self.runeStats[i][slot - 1].SetLabel(line)
-            i += 1

+ 6 - 70
src/RuneOptimizerGUI/classes/RuneOptimizerFrame.py

@@ -20,54 +20,8 @@ class RuneOptimizerFrame(wx.Frame):
     """
     The main application window.
 
-    Parameters
-    ----------
-    unitList : wx.ListCtrl
-        Selectable unit list with priorities.
-    unitContent : wx.BoxSizer
-        Holds every widget that is hidden until a unit is selected.
-    unitName : wx.StaticText
-        Label with the unit name.
-    statGrid : wx.Grid.grid
-        Table with the unit base and current stats.
-    runeList : wx.StaticText[6]
-        Labels with all the info about the currently equipped runes.
-    minStatSlider : wx.Slider[6]
-        List of sliders for the minimum selectors for each stat.
-    minStatText : wx.StaticText[6]
-        List of text inputs for the minimum selectors for each stat.
-    runeSets : wx.Choice[3]
-        List of selector to pik rune sets.
-    stats : wx.CheckListBox[2]
-        Tho selctors to choose stats allowed in optimization.
-    level : wx.Choice
-        Selector to pick the level for the rune optimization.
-    currentStats : int[10]
-        The current stats of the unit being optimized. (default is
-        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).
-    filterName : wx.TextCtrl
-        Text input to filter units names.
-    filterNames : wx.CheckBox
-        Checkbox to include or exclude units in storage.
-    filterNoRunes : wx.CheckBox
-        Checkbox to include or exclude units without runes.
-    filterNoTeams : wx.CheckBox
-        Checkbox to include or exclude units in no teams.
-
     Methods
     -------
-    processResults(jsonData)
-        Processes data obtained from RuneOptimizer.
-    populateUnitList(event)
-        Populates the unit list.
-    startOptimization(event)
-        Prepares and runs a command optimization.
-    minStatChangeBySlider(event)
-        Changes text when a slider is changed.
-    minStatChangeByTExt(event)
-        Changes the slider when the text is changed.
-    unitSelected(event)
-        Loads a unit info and enables optimizaton options.
     makeMenuBar(event)
         Creates the app menu bar.
     closeApp(event)
@@ -75,34 +29,18 @@ class RuneOptimizerFrame(wx.Frame):
     showAbout(event)
         Display an About dialog.
     updateFromJson(event)
-        Updates data from a JSON file.
+        Shows a dialog to update data from a JSON file.
     updateFromSwdb(event)
-        Updates data from a JSON file.
+        Updates data from a SWDB instance.
     updateFromSwarfarm(event)
-        Updates data from a JSON file.
+        Updates data from Swarfarm.
     updateFromSqlite(event)
-        Updates data from a JSON file.
+        Updates data from a SQLite file.
     showUnimplemented(parent, event)
         Displays a message for unimplemented features.
 
     """
 
-    unitList = None
-    unitContent = None
-    unitName = None
-    statGrid = None
-    runeList = None
-    minStatSlid = None
-    minStatText = None
-    runeSets = None
-    stats = None
-    level = None
-    currentStats = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
-    filterName = None
-    filterStorage = None
-    filterNoRunes = None
-    filterNoTeams = None
-
     def __init__(self, *args, **kw):
         """
         Initializes the class.
@@ -217,11 +155,9 @@ class RuneOptimizerFrame(wx.Frame):
 
         wx.MessageBox("RuneOptimizerAbout", wx.OK | wx.ICON_INFORMATION)
 
-    def updateFromJson(self, event):
+    def updateFromJson(self, event = None):
         """
-        Updates data from a JSON file.
-
-        TODO
+        Shows a dialog to update data from a JSON file.
 
         Parameters
         ----------

+ 16 - 2
src/RuneOptimizerGUI/classes/TabList.py

@@ -20,6 +20,17 @@ class TabList(wx.Listbook):
     """
     The main menu.
 
+    Parameters
+    ----------
+    frameUnits : PanelUnits
+        Unit details view.
+    frameTeams : PanelTeams
+        Team management view.
+    frameOptimizer : PanelOptimizer
+        Optimizer view.
+    frameResults : PanelUnits
+        Optimization results view.
+
     Methods
     -------
     OnPageChanged(event)
@@ -34,7 +45,10 @@ class TabList(wx.Listbook):
     frameOptimizer = None
     frameResults = None
 
-    def __init__(self, parent, id=wx.ID_ANY, pos=(0, 0), size=(800, 600), style=wx.LC_REPORT):
+    def __init__(
+      self, parent, id=wx.ID_ANY,
+      pos=(0, 0), size=(800, 600), style=wx.LC_REPORT
+    ):
         """
         Initializes the tablist.
 
@@ -74,7 +88,7 @@ class TabList(wx.Listbook):
           type=wx.BITMAP_TYPE_BMP
         )
         il.Add(bmp)
-        self.AssignImageList(il)
+         .AssignImageList(il)
 
         # Create the entries
         self.frameUnits = PanelUnits(self)

BIN
src/RuneOptimizerGUI/res/icon/progress.gif