color mixer
authorFrank DeMarco <if.self.end@gmail.com>
Thu, 7 Mar 2019 21:05:27 +0000 (16:05 -0500)
committerFrank DeMarco <if.self.end@gmail.com>
Thu, 7 Mar 2019 21:05:27 +0000 (16:05 -0500)
PictureProcessing.py
config

index 68f07dc..101bb4a 100644 (file)
@@ -128,6 +128,11 @@ class Editor(GameChild):
     LABEL_TILE_NEW = "NEW"
     LABEL_TILE_DELETE = "DELETE"
     LABEL_TILE_EDIT = "EDIT"
+    LABEL_MIX_COLOR = "ENTER: MIX", "A: MIX"
+    LABEL_ADD_COLOR = "ENTER: ADD", "A: ADD"
+    LABEL_RED = "\\17 RED \\16"
+    LABEL_GREEN = "\\17 GREEN \\16"
+    LABEL_BLUE = "\\17 BLUE \\16"
     HEADING_MARGIN = 60
     BUTTONS_MARGIN = 60
     VIEW_MARGIN = 120
@@ -145,6 +150,8 @@ class Editor(GameChild):
     TILE_LOAD_MENU_SHRINK = -100, -300
     TILE_LOAD_MENU_PADDING = 8
     TILE_LOAD_MENU_MARGIN = 2
+    BOX_PREVIEW_ALPHA = 200
+    MIXER_STEP = 10
 
     def __init__(self, parent):
         GameChild.__init__(self, parent)
@@ -163,14 +170,18 @@ class Editor(GameChild):
         self.at_test = False
         self.at_tile_menu = False
         self.at_tile_load = False
+        self.at_mixer = False
         self.level_index = 0
         self.tile_index = 0
         self.palette_index = 0
         self.tile_load_index = 0
+        self.mixer_index = 0
         self.loaded = False
         self.menu_hidden = False
         self.paint_pressed = False
         self.tile_menu_index = 0
+        self.mixer_color = MixableColor()
+        self.added_colors = []
 
     def reset(self):
         self.deactivate()
@@ -229,6 +240,18 @@ class Editor(GameChild):
         self.label_swap = self.get_label(
             self.LABEL_SWAP, align=self.ALIGN_TWO_THIRDS_BOTTOM,
             margin=self.VIEW_MARGIN)
+        self.label_mix_color = self.get_label(
+            self.LABEL_MIX_COLOR, align=self.ALIGN_TWO_THIRDS_BOTTOM,
+            margin=self.VIEW_MARGIN)
+        self.label_add_color = self.get_label(
+            self.LABEL_ADD_COLOR, align=self.ALIGN_TWO_THIRDS_BOTTOM,
+            margin=self.VIEW_MARGIN)
+        self.label_red = self.get_label(self.LABEL_RED)
+        self.label_red.location.centerx = dsr.centerx
+        self.label_green = self.get_label(self.LABEL_GREEN)
+        self.label_green.location.centerx = dsr.centerx
+        self.label_blue = self.get_label(self.LABEL_BLUE)
+        self.label_blue.location.centerx = dsr.centerx
         self.label_solved = self.get_label(self.LABEL_SOLVED)
         self.label_solved.location.bottomright = dsr.bottomright
         self.label_tile_load = self.get_label(self.LABEL_TILE_LOAD)
@@ -265,6 +288,8 @@ class Editor(GameChild):
             *([self.TILE_SIZE * self.TILE_BAR_SCALE] * 2))
         self.paint_cursor = self.get_cursor(*([self.CANVAS_SCALE] * 2))
         self.palette_cursor = self.get_cursor()
+        self.mixer_cursor = self.get_cursor(300, 100)
+        self.mixer_cursor.location.center = dsr.center
         self.box_cursor = self.get_cursor()
         self.tile_menu_cursor = self.get_label(self.TILE_MENU_CURSOR)
         self.tile_menu_cursor.location.top = self.tile_menu_background.location.top
@@ -467,8 +492,15 @@ class Editor(GameChild):
                     self.at_tile_load = False
                     self.at_tile_bar = True
                 elif self.at_palette:
-                    self.at_palette = False
-                    self.at_tile_edit = True
+                    if self.at_mixer:
+                        self.add_color()
+                        if not self.is_mixer_selected():
+                            self.palette_index = len(self.get_full_palette())
+                    elif self.is_mixer_selected():
+                        self.at_mixer = True
+                    else:
+                        self.at_palette = False
+                        self.at_tile_edit = True
             if compare(event, "cancel"):
                 if self.at_level_select:
                     self.deactivate()
@@ -492,8 +524,11 @@ class Editor(GameChild):
                     self.at_tile_edit = False
                     self.at_tile_bar = True
                 elif self.at_palette:
-                    self.at_palette = False
-                    self.at_tile_edit = True
+                    if self.at_mixer:
+                        self.at_mixer = False
+                    elif not self.is_mixer_selected():
+                        self.at_palette = False
+                        self.at_tile_edit = True
                 elif self.at_box:
                     self.at_box = False
                     self.at_view = True
@@ -524,6 +559,16 @@ class Editor(GameChild):
                         self.at_palette = True
                         if self.palette_index_is_at_left():
                             self.wrap_palette_index()
+                elif self.at_palette:
+                    if self.at_mixer:
+                        shift = [0, 0, 0]
+                        shift[self.mixer_index] += self.MIXER_STEP
+                        self.mixer_color.shift_rgb(*shift)
+                    elif self.palette_index_is_at_left():
+                        self.at_palette = False
+                        self.at_tile_edit = True
+                    else:
+                        self.wrap_palette_index()
                 if self.at_tile_load:
                     row_count = self.get_tile_load_row_count()
                     if (self.tile_load_index + 1) % row_count == 0:
@@ -538,12 +583,6 @@ class Editor(GameChild):
                     else:
                         self.tile_load_index += 1
                         self.tile_load_cursor.move(dx=self.get_tile_load_cursor_step())
-                elif self.at_palette:
-                    if self.palette_index_is_at_left():
-                        self.at_palette = False
-                        self.at_tile_edit = True
-                    else:
-                        self.wrap_palette_index()
                 if self.at_view:
                     self.at_view = False
                     self.at_test = True
@@ -560,10 +599,15 @@ class Editor(GameChild):
                         self.tile_load_index += row_count
                         self.tile_load_cursor.move(dy=self.get_tile_load_cursor_step())
                 if self.at_palette:
-                    self.palette_index += 1
+                    if self.at_mixer:
+                        self.mixer_index = (self.mixer_index + 1) % 3
+                    else:
+                        self.palette_index += 1
                 if self.at_view:
                     self.at_view = False
                     self.at_box = True
+                    if self.add_tile_selected():
+                        self.tile_index = 0
             elif compare(event, "left"):
                 if self.at_level_select:
                     self.level_index -= 1
@@ -591,6 +635,18 @@ class Editor(GameChild):
                         self.at_palette = True
                         if not self.palette_index_is_at_left():
                             self.wrap_palette_index()
+                elif self.at_palette:
+                    if self.at_mixer:
+                        shift = [0, 0, 0]
+                        shift[self.mixer_index] -= self.MIXER_STEP
+                        self.mixer_color.shift_rgb(*shift)
+                    elif self.is_mixer_selected():
+                        self.at_mixer = True
+                    elif not self.palette_index_is_at_left():
+                        self.at_palette = False
+                        self.at_tile_edit = True
+                    else:
+                        self.wrap_palette_index()
                 if self.at_tile_load:
                     row_count = self.get_tile_load_row_count()
                     if self.tile_load_index == 0:
@@ -600,12 +656,6 @@ class Editor(GameChild):
                     else:
                         self.tile_load_index -= 1
                         self.tile_load_cursor.move(dx=-self.get_tile_load_cursor_step())
-                elif self.at_palette:
-                    if not self.palette_index_is_at_left():
-                        self.at_palette = False
-                        self.at_tile_edit = True
-                    else:
-                        self.wrap_palette_index()
             elif compare(event, "up"):
                 if self.at_view:
                     self.at_view = False
@@ -620,7 +670,10 @@ class Editor(GameChild):
                         self.tile_load_index -= row_count
                         self.tile_load_cursor.move(dy=-self.get_tile_load_cursor_step())
                 if self.at_palette:
-                    self.palette_index -= 1
+                    if self.at_mixer:
+                        self.mixer_index = (self.mixer_index - 1) % 3
+                    else:
+                        self.palette_index -= 1
             elif compare(event, "paint"):
                 self.paint_pressed = True
                 if self.at_box:
@@ -629,9 +682,14 @@ class Editor(GameChild):
                     self.paint_tile()
             elif compare(event, "paint", cancel=True):
                 self.paint_pressed = False
-                if self.at_box:
+                if self.at_box and not self.add_tile_selected():
                     self.stamp()
-                    self.box.size = Vector(*([self.get_level_tile_size()] * 2))
+                self.box.size = Vector(*([self.get_level_tile_size()] * 2))
+            elif compare(event, "select"):
+                if self.at_box:
+                    self.tile_index += 1
+                    if self.tile_index == len(self.get_current_level().tiles):
+                        self.tile_index = 0
             if dx != 0 or dy != 0:
                 if self.at_box:
                     if self.paint_pressed:
@@ -647,6 +705,16 @@ class Editor(GameChild):
             elif self.palette_index < 0:
                 self.palette_index = self.get_palette_cell_count() - 1
 
+    def add_color(self):
+        palette = self.get_full_palette()
+        found = False
+        for color in palette:
+            if color == self.mixer_color:
+                found = True
+                break
+        if not found:
+            self.added_colors.append(Color(self.mixer_color.r, self.mixer_color.g, self.mixer_color.b))
+
     def set_level_title(self):
         level = self.get_current_level()
         if level.path is None:
@@ -882,7 +950,12 @@ class Editor(GameChild):
                     canvas = scale(tile, [self.CANVAS_SCALE * tile.get_width()] * 2)
                     rect = canvas.get_rect()
                     rect.center = ds.get_rect().center
-                    ds.blit(canvas, rect)
+                    if self.is_mixer_selected():
+                        surface = Surface(rect.size)
+                        surface.fill(self.mixer_color)
+                        ds.blit(surface, rect)
+                    else:
+                        ds.blit(canvas, rect)
                     palette = self.get_full_palette()
                     length = len(palette) + 1
                     color_left_height = canvas.get_height() / (length / 2 + length % 2)
@@ -921,21 +994,45 @@ class Editor(GameChild):
                     if self.at_tile_edit:
                         paint_flashing = True
                         palette_flashing = False
-                    else:
+                        mixer_flashing = False
+                    elif not self.at_mixer:
                         paint_flashing = False
                         palette_flashing = True
+                        mixer_flashing = False
+                    else:
+                        paint_flashing = False
+                        palette_flashing = False
+                        mixer_flashing = True
                     self.paint_cursor.set_flashing(paint_flashing)
                     self.paint_cursor.set_size(*([self.CANVAS_SCALE] * 2))
                     self.palette_cursor.set_flashing(palette_flashing)
                     self.palette_cursor.set_size(palette_rect.w, color_left_height)
+                    if self.at_mixer or self.is_mixer_selected():
+                        self.label_red.location.centery = rect.top + (rect.centery - rect.top) / 2
+                        self.label_green.location.centery = rect.centery
+                        self.label_blue.location.centery = rect.bottom - (rect.bottom - rect.centery) / 2
+                        self.mixer_cursor.set_flashing(mixer_flashing)
+                        labels = self.label_red, self.label_green, self.label_blue
+                        active_label = labels[self.mixer_index]
+                        for label in labels:
+                            label.update()
+                        self.mixer_cursor.set_size(*active_label.location.size)
+                        self.mixer_cursor.location.center = active_label.location.center
+                        self.mixer_cursor.update()
                     self.paint_cursor.location.topleft = \
                         rect.left + self.brush_position.x * self.CANVAS_SCALE, \
                         rect.top + self.brush_position.y * self.CANVAS_SCALE
-                    self.paint_cursor.update()
+                    if not self.at_mixer and not self.is_mixer_selected():
+                        self.paint_cursor.update()
                     if self.at_tile_edit:
                         self.label_paint.update()
                     elif self.at_palette:
-                        self.label_select.update()
+                        if self.at_mixer:
+                            self.label_add_color.update()
+                        elif self.is_mixer_selected():
+                            self.label_mix_color.update()
+                        else:
+                            self.label_select.update()
                     if self.palette_index < length / 2 + length % 2:
                         left = palette_left_rect.left
                         top = color_left_height * self.palette_index
@@ -959,6 +1056,13 @@ class Editor(GameChild):
                 else:
                     self.label_drag.location.bottom = ds.get_height() - self.VIEW_MARGIN
                     self.label_back_box.location.bottom = ds.get_height() - self.VIEW_MARGIN
+                surface = Surface(self.box.location.size)
+                tile = self.get_current_level().tiles[self.tile_index]
+                for x in xrange(0, surface.get_width(), self.get_level_tile_size()):
+                    for y in xrange(0, surface.get_height(), self.get_level_tile_size()):
+                        surface.blit(tile, (x, y))
+                surface.set_alpha(self.BOX_PREVIEW_ALPHA)
+                ds.blit(surface, self.box.location.topleft)
                 self.box.move(-1, -1)
                 self.box.update()
                 self.box.move(1, 1)
@@ -974,8 +1078,11 @@ class Editor(GameChild):
                         self.label_solved.update()
                 interface.update()
 
+    def is_mixer_selected(self):
+        return self.palette_index == len(self.get_full_palette())
+
     def get_full_palette(self):
-        return self.default_palette + self.get_current_colors()
+        return self.default_palette + self.get_current_colors() + self.added_colors
 
     def get_current_tile(self):
         return self.get_current_level().original_tiles[self.tile_index]
@@ -987,11 +1094,75 @@ class Editor(GameChild):
             for x in xrange(0, tile.get_width()):
                 for y in xrange(0, tile.get_height()):
                     color = tile.get_at((x, y))
-                    if color not in colors and color not in self.default_palette:
+                    if color not in colors and color not in self.default_palette and color not in self.added_colors:
                         colors.append(color)
         return colors
 
 
+class MixableColor(Color):
+
+    def __init__(self, r=None, g=None, b=None):
+        if r is None:
+            r = 255
+        if g is None:
+            g = 0
+        if b is None:
+            b = 0
+        Color.__init__(self, r, g, b)
+
+    def shift_hsla(self, dh=0, ds=0, dl=0, da=0, wrap=False):
+        h, s, l, a = self.hsla
+        if wrap:
+            self.hsla = int(h + dh) % 360, int(s + ds) % 101, int(l + dl) % 101, int(a + da) % 101
+        else:
+            h += dh
+            s += ds
+            l += dl
+            a += da
+            if h < 0:
+                h = 0
+            elif h > 360:
+                h = 360
+            if s < 0:
+                s = 0
+            elif s > 100:
+                s = 100
+            if l < 0:
+                l = 0
+            elif l > 100:
+                l = 100
+            if a < 0:
+                a = 0
+            elif a > 100:
+                a = 100
+            self.hsla = h, s, l, a
+
+    def shift_rgb(self, r=0, g=0, b=0, wrap=False):
+        if wrap:
+            self.r = (self.r + r) % 255
+            self.g = (self.g + g) % 255
+            self.b = (self.b + b) % 255
+        else:
+            red = self.r + r
+            green = self.g + g
+            blue = self.b + b
+            if red < 0:
+                red = 0
+            elif red > 255:
+                red = 255
+            if green < 0:
+                green = 0
+            elif green > 255:
+                green = 255
+            if blue < 0:
+                blue = 0
+            elif blue > 255:
+                blue = 255
+            self.r = red
+            self.g = green
+            self.b = blue
+
+
 class FlashingCursor(Sprite):
 
     THICKNESS = 3
diff --git a/config b/config
index 287a61b..8f8c44c 100644 (file)
--- a/config
+++ b/config
@@ -19,6 +19,7 @@ action = K_RETURN
 toggle = K_TAB
 context = K_F3
 paint = K_z
+select = K_LSHIFT
 
 [joy]
 advance = 9
@@ -29,10 +30,11 @@ delay-axis = .15
 vertical-axis = 1
 horizontal-axis = 0
 paint = 1
+select = 8
 
 [mouse]
 visible = no
-resets = yes
+resets = no
 
 [video-recordings]
 framerate = 100