6 Commits

Author SHA1 Message Date
Akash Bora
5ab50a9b91 Update Readme.md 2025-08-09 15:58:44 +05:30
Akash Bora
66d12839b9 Update Readme.md 2025-08-09 15:57:38 +05:30
Akash Bora
c78cea8890 Update Readme.md 2025-08-09 15:52:24 +05:30
Akash Bora
b0940006b6 Update LICENSE 2025-08-09 15:52:11 +05:30
Akash Bora
c6a7f9f67a New Version 2.4
What's new?
- Fixed RangeSlider widget for mac OS
- Improved Setup for macOS
- Fixed video open function for macOS
2025-08-09 15:51:38 +05:30
Akash Bora
08fb701a44 Add files via upload 2025-08-09 15:47:34 +05:30
18 changed files with 470 additions and 37 deletions

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 Akash Bora
Copyright (c) 2025 Akash Bora
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -2,11 +2,9 @@
CTkRangeSlider
Range slider for customtkinter
Author: Akash Bora
Version: 0.2
Version: 0.3
"""
from __future__ import annotations
import math
import tkinter
import sys
@@ -23,12 +21,90 @@ class CustomDrawEngine:
It is tailored towards the range slider.
"""
preferred_drawing_method: str = "font_shapes" # 'polygon_shapes', 'font_shapes', 'circle_shapes'
# Use circle_shapes on macOS to avoid rectangular slider heads, font_shapes elsewhere
preferred_drawing_method: str = "circle_shapes" if sys.platform == "darwin" else "font_shapes"
def __init__(self, canvas: CTkCanvas):
self._canvas = canvas
def _DrawEngine__draw_rounded_rect_with_border_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int,
def __calc_optimal_corner_radius(self, user_corner_radius: Union[float, int]) -> Union[float, int]:
# optimize for drawing with polygon shapes
if self.preferred_drawing_method == "polygon_shapes":
if sys.platform == "darwin":
return user_corner_radius
else:
return round(user_corner_radius)
# optimize for drawing with antialiased font shapes
elif self.preferred_drawing_method == "font_shapes":
return round(user_corner_radius)
# optimize for drawing with circles and rects
elif self.preferred_drawing_method == "circle_shapes":
user_corner_radius = 0.5 * round(user_corner_radius / 0.5) # round to 0.5 steps
# make sure the value is always with .5 at the end for smoother corners
if user_corner_radius == 0:
return 0
elif user_corner_radius % 1 == 0:
return user_corner_radius + 0.5
else:
return user_corner_radius
def __draw_rounded_rect_with_border_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int) -> bool:
requires_recoloring = False
# create border button parts (only if border exists)
if border_width > 0:
if not self._canvas.find_withtag("border_parts"):
self._canvas.create_polygon((0, 0, 0, 0), tags=("border_line_1", "border_parts"))
requires_recoloring = True
self._canvas.coords("border_line_1",
(corner_radius,
corner_radius,
width - corner_radius,
corner_radius,
width - corner_radius,
height - corner_radius,
corner_radius,
height - corner_radius))
self._canvas.itemconfig("border_line_1",
joinstyle=tkinter.ROUND,
width=corner_radius * 2)
else:
self._canvas.delete("border_parts")
# create inner button parts
if not self._canvas.find_withtag("inner_parts"):
self._canvas.create_polygon((0, 0, 0, 0), tags=("inner_line_1", "inner_parts"), joinstyle=tkinter.ROUND)
requires_recoloring = True
if corner_radius <= border_width:
bottom_right_shift = -1 # weird canvas rendering inaccuracy that has to be corrected in some cases
else:
bottom_right_shift = 0
self._canvas.coords("inner_line_1",
border_width + inner_corner_radius,
border_width + inner_corner_radius,
width - (border_width + inner_corner_radius) + bottom_right_shift,
border_width + inner_corner_radius,
width - (border_width + inner_corner_radius) + bottom_right_shift,
height - (border_width + inner_corner_radius) + bottom_right_shift,
border_width + inner_corner_radius,
height - (border_width + inner_corner_radius) + bottom_right_shift)
self._canvas.itemconfig("inner_line_1",
width=inner_corner_radius * 2)
if requires_recoloring: # new parts were added -> manage z-order
self._canvas.tag_lower("inner_parts")
self._canvas.tag_lower("border_parts")
return requires_recoloring
def __draw_rounded_rect_with_border_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int,
exclude_parts: tuple) -> bool:
requires_recoloring = False
@@ -165,7 +241,257 @@ class CustomDrawEngine:
self._canvas.tag_lower("border_parts")
return requires_recoloring
def __draw_rounded_rect_with_border_circle_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int) -> bool:
requires_recoloring = False
# create border parts (only if border exists)
if border_width > 0:
if corner_radius > 0:
# create canvas border corner parts if not already created
if not self._canvas.find_withtag("border_oval_1"):
self._canvas.create_oval(0, 0, 0, 0, tags=("border_oval_1", "border_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("border_oval_2", "border_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("border_oval_3", "border_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("border_oval_4", "border_parts"), width=0)
requires_recoloring = True
# set positions of border corner parts
self._canvas.coords("border_oval_1", 0, 0, 2 * corner_radius, 2 * corner_radius)
self._canvas.coords("border_oval_2", width - 2 * corner_radius, 0, width, 2 * corner_radius)
self._canvas.coords("border_oval_3", width - 2 * corner_radius, height - 2 * corner_radius, width, height)
self._canvas.coords("border_oval_4", 0, height - 2 * corner_radius, 2 * corner_radius, height)
# create canvas border rectangle parts
if not self._canvas.find_withtag("border_rectangle_1"):
self._canvas.create_rectangle(0, 0, 0, 0, tags=("border_rectangle_1", "border_parts"), width=0)
self._canvas.create_rectangle(0, 0, 0, 0, tags=("border_rectangle_2", "border_parts"), width=0)
requires_recoloring = True
# set positions of border rectangle parts
self._canvas.coords("border_rectangle_1", corner_radius, 0, width - corner_radius, height)
self._canvas.coords("border_rectangle_2", 0, corner_radius, width, height - corner_radius)
else:
self._canvas.delete("border_parts")
# create inner parts
if not self._canvas.find_withtag("inner_rectangle_1"):
self._canvas.create_rectangle(0, 0, 0, 0, tags=("inner_rectangle_1", "inner_parts"), width=0)
requires_recoloring = True
if inner_corner_radius > 0:
if not self._canvas.find_withtag("inner_oval_1"):
self._canvas.create_oval(0, 0, 0, 0, tags=("inner_oval_1", "inner_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("inner_oval_2", "inner_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("inner_oval_3", "inner_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("inner_oval_4", "inner_parts"), width=0)
requires_recoloring = True
# set positions of inner corner parts
self._canvas.coords("inner_oval_1", border_width, border_width, border_width + 2 * inner_corner_radius, border_width + 2 * inner_corner_radius)
self._canvas.coords("inner_oval_2", width - border_width - 2 * inner_corner_radius, border_width, width - border_width, border_width + 2 * inner_corner_radius)
self._canvas.coords("inner_oval_3", width - border_width - 2 * inner_corner_radius, height - border_width - 2 * inner_corner_radius, width - border_width, height - border_width)
self._canvas.coords("inner_oval_4", border_width, height - border_width - 2 * inner_corner_radius, border_width + 2 * inner_corner_radius, height - border_width)
else:
self._canvas.delete("inner_oval_1", "inner_oval_2", "inner_oval_3", "inner_oval_4")
# set position of inner rectangle part
self._canvas.coords("inner_rectangle_1", border_width + inner_corner_radius, border_width, width - border_width - inner_corner_radius, height - border_width)
if requires_recoloring:
self._canvas.tag_lower("inner_parts")
self._canvas.tag_lower("border_parts")
return requires_recoloring
def __draw_rounded_progress_bar_with_border_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int,
progress_value_1: float, progress_value_2: float, orientation: str) -> bool:
requires_recoloring = self.__draw_rounded_rect_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius)
if corner_radius <= border_width:
bottom_right_shift = 0 # weird canvas rendering inaccuracy that has to be corrected in some cases
else:
bottom_right_shift = 0
# create progress parts
if not self._canvas.find_withtag("progress_parts"):
self._canvas.create_polygon((0, 0, 0, 0), tags=("progress_line_1", "progress_parts"), joinstyle=tkinter.ROUND)
self._canvas.tag_raise("progress_parts", "inner_parts")
requires_recoloring = True
if orientation == "w":
self._canvas.coords("progress_line_1",
border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_1,
border_width + inner_corner_radius,
border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_2,
border_width + inner_corner_radius,
border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_2,
height - (border_width + inner_corner_radius) + bottom_right_shift,
border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_1,
height - (border_width + inner_corner_radius) + bottom_right_shift)
elif orientation == "s":
self._canvas.coords("progress_line_1",
border_width + inner_corner_radius,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_2),
width - (border_width + inner_corner_radius),
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_2),
width - (border_width + inner_corner_radius),
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_1),
border_width + inner_corner_radius,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_1))
self._canvas.itemconfig("progress_line_1", width=inner_corner_radius * 2)
return requires_recoloring
def __draw_rounded_progress_bar_with_border_font_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int,
progress_value_1: float, progress_value_2: float, orientation: str) -> bool:
requires_recoloring, requires_recoloring_2 = False, False
if inner_corner_radius > 0:
# create canvas border corner parts if not already created
if not self._canvas.find_withtag("progress_oval_1_a"):
self._canvas.create_aa_circle(0, 0, 0, tags=("progress_oval_1_a", "progress_corner_part", "progress_parts"), anchor=tkinter.CENTER)
self._canvas.create_aa_circle(0, 0, 0, tags=("progress_oval_1_b", "progress_corner_part", "progress_parts"), anchor=tkinter.CENTER, angle=180)
self._canvas.create_aa_circle(0, 0, 0, tags=("progress_oval_2_a", "progress_corner_part", "progress_parts"), anchor=tkinter.CENTER)
self._canvas.create_aa_circle(0, 0, 0, tags=("progress_oval_2_b", "progress_corner_part", "progress_parts"), anchor=tkinter.CENTER, angle=180)
requires_recoloring = True
if not self._canvas.find_withtag("progress_oval_3_a") and round(inner_corner_radius) * 2 < height - 2 * border_width:
self._canvas.create_aa_circle(0, 0, 0, tags=("progress_oval_3_a", "progress_corner_part", "progress_parts"), anchor=tkinter.CENTER)
self._canvas.create_aa_circle(0, 0, 0, tags=("progress_oval_3_b", "progress_corner_part", "progress_parts"), anchor=tkinter.CENTER, angle=180)
self._canvas.create_aa_circle(0, 0, 0, tags=("progress_oval_4_a", "progress_corner_part", "progress_parts"), anchor=tkinter.CENTER)
self._canvas.create_aa_circle(0, 0, 0, tags=("progress_oval_4_b", "progress_corner_part", "progress_parts"), anchor=tkinter.CENTER, angle=180)
requires_recoloring = True
elif self._canvas.find_withtag("progress_oval_3_a") and not round( inner_corner_radius) * 2 < height - 2 * border_width:
self._canvas.delete("progress_oval_3_a", "progress_oval_3_b", "progress_oval_4_a", "progress_oval_4_b")
if not self._canvas.find_withtag("progress_rectangle_1"):
self._canvas.create_rectangle(0, 0, 0, 0, tags=("progress_rectangle_1", "progress_rectangle_part", "progress_parts"), width=0)
requires_recoloring = True
if not self._canvas.find_withtag("progress_rectangle_2") and inner_corner_radius * 2 < height - (border_width * 2):
self._canvas.create_rectangle(0, 0, 0, 0, tags=("progress_rectangle_2", "progress_rectangle_part", "progress_parts"), width=0)
requires_recoloring = True
elif self._canvas.find_withtag("progress_rectangle_2") and not inner_corner_radius * 2 < height - (border_width * 2):
self._canvas.delete("progress_rectangle_2")
# horizontal orientation from the bottom
if orientation == "w":
requires_recoloring_2 = self.__draw_rounded_rect_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius,
())
# set positions of progress corner parts
self._canvas.coords("progress_oval_1_a", border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_1,
border_width + inner_corner_radius, inner_corner_radius)
self._canvas.coords("progress_oval_1_b", border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_1,
border_width + inner_corner_radius, inner_corner_radius)
self._canvas.coords("progress_oval_2_a", border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_2,
border_width + inner_corner_radius, inner_corner_radius)
self._canvas.coords("progress_oval_2_b", border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_2,
border_width + inner_corner_radius, inner_corner_radius)
self._canvas.coords("progress_oval_3_a", border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_2,
height - border_width - inner_corner_radius, inner_corner_radius)
self._canvas.coords("progress_oval_3_b", border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_2,
height - border_width - inner_corner_radius, inner_corner_radius)
self._canvas.coords("progress_oval_4_a", border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_1,
height - border_width - inner_corner_radius, inner_corner_radius)
self._canvas.coords("progress_oval_4_b", border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_1,
height - border_width - inner_corner_radius, inner_corner_radius)
# set positions of progress rect parts
self._canvas.coords("progress_rectangle_1",
border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_1,
border_width,
border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_2,
height - border_width)
self._canvas.coords("progress_rectangle_2",
border_width + 2 * inner_corner_radius + (width - 2 * inner_corner_radius - 2 * border_width) * progress_value_1,
border_width + inner_corner_radius,
border_width + 2 * inner_corner_radius + (width - 2 * inner_corner_radius - 2 * border_width) * progress_value_2,
height - inner_corner_radius - border_width)
# vertical orientation from the bottom
if orientation == "s":
requires_recoloring_2 = self.__draw_rounded_rect_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius,
())
# set positions of progress corner parts
self._canvas.coords("progress_oval_1_a", border_width + inner_corner_radius,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_2), inner_corner_radius)
self._canvas.coords("progress_oval_1_b", border_width + inner_corner_radius,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_2), inner_corner_radius)
self._canvas.coords("progress_oval_2_a", width - border_width - inner_corner_radius,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_2), inner_corner_radius)
self._canvas.coords("progress_oval_2_b", width - border_width - inner_corner_radius,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_2), inner_corner_radius)
self._canvas.coords("progress_oval_3_a", width - border_width - inner_corner_radius,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_1), inner_corner_radius)
self._canvas.coords("progress_oval_3_b", width - border_width - inner_corner_radius,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_1), inner_corner_radius)
self._canvas.coords("progress_oval_4_a", border_width + inner_corner_radius,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_1), inner_corner_radius)
self._canvas.coords("progress_oval_4_b", border_width + inner_corner_radius,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_1), inner_corner_radius)
# set positions of progress rect parts
self._canvas.coords("progress_rectangle_1",
border_width + inner_corner_radius,
border_width + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_2),
width - border_width - inner_corner_radius,
border_width + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_1))
self._canvas.coords("progress_rectangle_2",
border_width,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_2),
width - border_width,
border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_1))
return requires_recoloring or requires_recoloring_2
def __draw_rounded_progress_bar_with_border_circle_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int,
progress_value_1: float, progress_value_2: float, orientation: str) -> bool:
requires_recoloring = self.__draw_rounded_rect_with_border_circle_shapes(width, height, corner_radius, border_width, inner_corner_radius)
# create progress parts
if not self._canvas.find_withtag("progress_rectangle_1"):
self._canvas.create_rectangle(0, 0, 0, 0, tags=("progress_rectangle_1", "progress_parts"), width=0)
requires_recoloring = True
if orientation == "w":
x1 = border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_1
x2 = border_width + inner_corner_radius + (width - 2 * border_width - 2 * inner_corner_radius) * progress_value_2
self._canvas.coords("progress_rectangle_1", x1, border_width, x2, height - border_width)
elif orientation == "s":
y1 = border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_2)
y2 = border_width + inner_corner_radius + (height - 2 * border_width - 2 * inner_corner_radius) * (1 - progress_value_1)
self._canvas.coords("progress_rectangle_1", border_width, y1, width - border_width, y2)
if inner_corner_radius > 0:
if not self._canvas.find_withtag("progress_oval_1"):
self._canvas.create_oval(0, 0, 0, 0, tags=("progress_oval_1", "progress_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("progress_oval_2", "progress_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("progress_oval_3", "progress_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("progress_oval_4", "progress_parts"), width=0)
requires_recoloring = True
if orientation == "w":
self._canvas.coords("progress_oval_1", x1 - inner_corner_radius, border_width, x1 + inner_corner_radius, border_width + 2 * inner_corner_radius)
self._canvas.coords("progress_oval_2", x2 - inner_corner_radius, border_width, x2 + inner_corner_radius, border_width + 2 * inner_corner_radius)
self._canvas.coords("progress_oval_3", x2 - inner_corner_radius, height - border_width - 2 * inner_corner_radius, x2 + inner_corner_radius, height - border_width)
self._canvas.coords("progress_oval_4", x1 - inner_corner_radius, height - border_width - 2 * inner_corner_radius, x1 + inner_corner_radius, height - border_width)
elif orientation == "s":
self._canvas.coords("progress_oval_1", border_width, y1 - inner_corner_radius, border_width + 2 * inner_corner_radius, y1 + inner_corner_radius)
self._canvas.coords("progress_oval_2", width - border_width - 2 * inner_corner_radius, y1 - inner_corner_radius, width - border_width, y1 + inner_corner_radius)
self._canvas.coords("progress_oval_3", width - border_width - 2 * inner_corner_radius, y2 - inner_corner_radius, width - border_width, y2 + inner_corner_radius)
self._canvas.coords("progress_oval_4", border_width, y2 - inner_corner_radius, border_width + 2 * inner_corner_radius, y2 + inner_corner_radius)
else:
self._canvas.delete("progress_oval_1", "progress_oval_2", "progress_oval_3", "progress_oval_4")
return requires_recoloring
def draw_rounded_slider_with_border_and_2_button(self, width: Union[float, int], height: Union[float, int], corner_radius: Union[float, int],
border_width: Union[float, int], button_length: Union[float, int], button_corner_radius: Union[float, int],
slider_value: float, slider_2_value: float, orientation: str) -> bool:
@@ -182,25 +508,28 @@ class CustomDrawEngine:
button_length = round(button_length)
border_width = round(border_width)
button_corner_radius = round(button_corner_radius)
corner_radius = DrawEngine._DrawEngine__calc_optimal_corner_radius(self, corner_radius) # optimize corner_radius for different drawing methods (different rounding)
corner_radius = self.__calc_optimal_corner_radius(corner_radius) # optimize corner_radius for different drawing methods (different rounding)
if corner_radius >= border_width:
inner_corner_radius = corner_radius - border_width
else:
inner_corner_radius = 0
if self.preferred_drawing_method == "polygon_shapes" or self.preferred_drawing_method == "circle_shapes":
if self.preferred_drawing_method == "polygon_shapes":
return self.__draw_rounded_slider_with_border_and_2_button_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius,
button_length, button_corner_radius, slider_value, slider_2_value, orientation)
elif self.preferred_drawing_method == "font_shapes":
return self.__draw_rounded_slider_with_border_and_2_button_font_shapes(width, height, corner_radius, border_width, inner_corner_radius,
button_length, button_corner_radius, slider_value, slider_2_value, orientation)
elif self.preferred_drawing_method == "circle_shapes":
return self.__draw_rounded_slider_with_border_and_2_button_circle_shapes(width, height, corner_radius, border_width, inner_corner_radius,
button_length, button_corner_radius, slider_value, slider_2_value, orientation)
def __draw_rounded_slider_with_border_and_2_button_polygon_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int,
button_length: int, button_corner_radius: int, slider_value: float, slider_2_value: float, orientation: str) -> bool:
# draw normal progressbar
requires_recoloring = DrawEngine._DrawEngine__draw_rounded_progress_bar_with_border_polygon_shapes(self, width, height, corner_radius, border_width, inner_corner_radius,
requires_recoloring = self.__draw_rounded_progress_bar_with_border_polygon_shapes(width, height, corner_radius, border_width, inner_corner_radius,
slider_value, slider_2_value, orientation)
# create slider button part
@@ -258,8 +587,7 @@ class CustomDrawEngine:
button_length: int, button_corner_radius: int, slider_value: float, slider_2_value: float, orientation: str) -> bool:
# draw normal progressbar
requires_recoloring = DrawEngine._DrawEngine__draw_rounded_progress_bar_with_border_font_shapes(self, width, height, corner_radius, border_width,
inner_corner_radius, slider_value, slider_2_value, orientation)
requires_recoloring = self.__draw_rounded_progress_bar_with_border_font_shapes(width, height, corner_radius, border_width, inner_corner_radius, slider_value, slider_2_value, orientation)
# create 4 circles (if not needed, then less)
if not self._canvas.find_withtag("slider_oval_1_a"):
@@ -285,14 +613,14 @@ class CustomDrawEngine:
self._canvas.create_aa_circle(0, 0, 0, tags=("slider_oval_3_a", "slider_corner_part", "slider_parts", "slider_0_parts"), anchor=tkinter.CENTER)
self._canvas.create_aa_circle(0, 0, 0, tags=("slider_oval_3_b", "slider_corner_part", "slider_parts", "slider_0_parts"), anchor=tkinter.CENTER, angle=180)
requires_recoloring = True
elif self._canvas.find_withtag("border_oval_3_a") and not (button_length > 0 and height > 2 * button_corner_radius):
elif self._canvas.find_withtag("slider_oval_3_a") and not (button_length > 0 and height > 2 * button_corner_radius):
self._canvas.delete("slider_oval_3_a", "slider_oval_3_b")
# create the 2 rectangles (if needed)
if not self._canvas.find_withtag("slider_rectangle_1") and button_length > 0:
self._canvas.create_rectangle(0, 0, 0, 0, tags=("slider_rectangle_1", "slider_rectangle_part", "slider_parts", "slider_0_parts"), width=0)
requires_recoloring = True
elif self._canvas.find_withtag("slider_rectangle_1") and not button_length > 0:
elif self._canvas.find_withtag("slider елдер_1") and not button_length > 0:
self._canvas.delete("slider_rectangle_1")
if not self._canvas.find_withtag("slider_rectangle_2") and height > 2 * button_corner_radius:
@@ -338,7 +666,7 @@ class CustomDrawEngine:
button_corner_radius, slider_y_position - (button_length / 2) - button_corner_radius,
width - button_corner_radius, slider_y_position + (button_length / 2) + button_corner_radius)
######## second button ##########
# second button
# create 4 circles (if not needed, then less)
if not self._canvas.find_withtag("slider_oval_2_1_a"):
self._canvas.create_aa_circle(0, 0, 0, tags=("slider_oval_2_1_a", "slider_corner_part", "slider_parts", "slider_1_parts"), anchor=tkinter.CENTER)
@@ -363,7 +691,7 @@ class CustomDrawEngine:
self._canvas.create_aa_circle(0, 0, 0, tags=("slider_oval_2_3_a", "slider_corner_part", "slider_parts", "slider_1_parts"), anchor=tkinter.CENTER)
self._canvas.create_aa_circle(0, 0, 0, tags=("slider_oval_2_3_b", "slider_corner_part", "slider_parts", "slider_1_parts"), anchor=tkinter.CENTER, angle=180)
requires_recoloring = True
elif self._canvas.find_withtag("border_oval_2_3_a") and not (button_length > 0 and height > 2 * button_corner_radius):
elif self._canvas.find_withtag("slider_oval_2_3_a") and not (button_length > 0 and height > 2 * button_corner_radius):
self._canvas.delete("slider_oval_2_3_a", "slider_oval_2_3_b")
# create the 2 rectangles (if needed)
@@ -421,6 +749,67 @@ class CustomDrawEngine:
return requires_recoloring
def __draw_rounded_slider_with_border_and_2_button_circle_shapes(self, width: int, height: int, corner_radius: int, border_width: int, inner_corner_radius: int,
button_length: int, button_corner_radius: int, slider_value: float, slider_2_value: float, orientation: str) -> bool:
requires_recoloring = self.__draw_rounded_progress_bar_with_border_circle_shapes(width, height, corner_radius, border_width, inner_corner_radius, slider_value, slider_2_value, orientation)
# create slider button parts
if not self._canvas.find_withtag("slider_0_parts"):
self._canvas.create_oval(0, 0, 0, 0, tags=("slider_oval_1", "slider_parts", "slider_0_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("slider_oval_2", "slider_parts", "slider_0_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("slider_oval_3", "slider_parts", "slider_0_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("slider_oval_4", "slider_parts", "slider_0_parts"), width=0)
self._canvas.create_rectangle(0, 0, 0, 0, tags=("slider_rectangle_1", "slider_parts", "slider_0_parts"), width=0)
self._canvas.create_rectangle(0, 0, 0, 0, tags=("slider_rectangle_2", "slider_parts", "slider_0_parts"), width=0)
requires_recoloring = True
if not self._canvas.find_withtag("slider_1_parts"):
self._canvas.create_oval(0, 0, 0, 0, tags=("slider_oval_2_1", "slider_parts", "slider_1_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("slider_oval_2_2", "slider_parts", "slider_1_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("slider_oval_2_3", "slider_parts", "slider_1_parts"), width=0)
self._canvas.create_oval(0, 0, 0, 0, tags=("slider_oval_2_4", "slider_parts", "slider_1_parts"), width=0)
self._canvas.create_rectangle(0, 0, 0, 0, tags=("slider_rectangle_2_1", "slider_parts", "slider_1_parts"), width=0)
self._canvas.create_rectangle(0, 0, 0, 0, tags=("slider_rectangle_2_2", "slider_parts", "slider_1_parts"), width=0)
requires_recoloring = True
if orientation == "w":
slider_x_position = corner_radius + (button_length / 2) + (width - 2 * corner_radius - button_length) * slider_value
self._canvas.coords("slider_oval_1", slider_x_position - button_length / 2 - button_corner_radius, 0, slider_x_position - button_length / 2 + button_corner_radius, 2 * button_corner_radius)
self._canvas.coords("slider_oval_2", slider_x_position + button_length / 2 - button_corner_radius, 0, slider_x_position + button_length / 2 + button_corner_radius, 2 * button_corner_radius)
self._canvas.coords("slider_oval_3", slider_x_position + button_length / 2 - button_corner_radius, height - 2 * button_corner_radius, slider_x_position + button_length / 2 + button_corner_radius, height)
self._canvas.coords("slider_oval_4", slider_x_position - button_length / 2 - button_corner_radius, height - 2 * button_corner_radius, slider_x_position - button_length / 2 + button_corner_radius, height)
self._canvas.coords("slider_rectangle_1", slider_x_position - button_length / 2, 0, slider_x_position + button_length / 2, height)
self._canvas.coords("slider_rectangle_2", slider_x_position - button_length / 2 - button_corner_radius, button_corner_radius, slider_x_position + button_length / 2 + button_corner_radius, height - button_corner_radius)
slider_x_position = corner_radius + (button_length / 2) + (width - 2 * corner_radius - button_length) * slider_2_value
self._canvas.coords("slider_oval_2_1", slider_x_position - button_length / 2 - button_corner_radius, 0, slider_x_position - button_length / 2 + button_corner_radius, 2 * button_corner_radius)
self._canvas.coords("slider_oval_2_2", slider_x_position + button_length / 2 - button_corner_radius, 0, slider_x_position + button_length / 2 + button_corner_radius, 2 * button_corner_radius)
self._canvas.coords("slider_oval_2_3", slider_x_position + button_length / 2 - button_corner_radius, height - 2 * button_corner_radius, slider_x_position + button_length / 2 + button_corner_radius, height)
self._canvas.coords("slider_oval_2_4", slider_x_position - button_length / 2 - button_corner_radius, height - 2 * button_corner_radius, slider_x_position - button_length / 2 + button_corner_radius, height)
self._canvas.coords("slider_rectangle_2_1", slider_x_position - button_length / 2, 0, slider_x_position + button_length / 2, height)
self._canvas.coords("slider_rectangle_2_2", slider_x_position - button_length / 2 - button_corner_radius, button_corner_radius, slider_x_position + button_length / 2 + button_corner_radius, height - button_corner_radius)
elif orientation == "s":
slider_y_position = corner_radius + (button_length / 2) + (height - 2 * corner_radius - button_length) * (1 - slider_value)
self._canvas.coords("slider_oval_1", 0, slider_y_position - button_length / 2 - button_corner_radius, 2 * button_corner_radius, slider_y_position - button_length / 2 + button_corner_radius)
self._canvas.coords("slider_oval_2", 0, slider_y_position + button_length / 2 - button_corner_radius, 2 * button_corner_radius, slider_y_position + button_length / 2 + button_corner_radius)
self._canvas.coords("slider_oval_3", width - 2 * button_corner_radius, slider_y_position + button_length / 2 - button_corner_radius, width, slider_y_position + button_length / 2 + button_corner_radius)
self._canvas.coords("slider_oval_4", width - 2 * button_corner_radius, slider_y_position - button_length / 2 - button_corner_radius, width, slider_y_position - button_length / 2 + button_corner_radius)
self._canvas.coords("slider_rectangle_1", 0, slider_y_position - button_length / 2, width, slider_y_position + button_length / 2)
self._canvas.coords("slider_rectangle_2", button_corner_radius, slider_y_position - button_length / 2 - button_corner_radius, width - button_corner_radius, slider_y_position + button_length / 2 + button_corner_radius)
slider_y_position = corner_radius + (button_length / 2) + (height - 2 * corner_radius - button_length) * (1 - slider_2_value)
self._canvas.coords("slider_oval_2_1", 0, slider_y_position - button_length / 2 - button_corner_radius, 2 * button_corner_radius, slider_y_position - button_length / 2 + button_corner_radius)
self._canvas.coords("slider_oval_2_2", 0, slider_y_position + button_length / 2 - button_corner_radius, 2 * button_corner_radius, slider_y_position + button_length / 2 + button_corner_radius)
self._canvas.coords("slider_oval_2_3", width - 2 * button_corner_radius, slider_y_position + button_length / 2 - button_corner_radius, width, slider_y_position + button_length / 2 + button_corner_radius)
self._canvas.coords("slider_oval_2_4", width - 2 * button_corner_radius, slider_y_position - button_length / 2 - button_corner_radius, width, slider_y_position - button_length / 2 + button_corner_radius)
self._canvas.coords("slider_rectangle_2_1", 0, slider_y_position - button_length / 2, width, slider_y_position + button_length / 2)
self._canvas.coords("slider_rectangle_2_2", button_corner_radius, slider_y_position - button_length / 2 - button_corner_radius, width - button_corner_radius, slider_y_position + button_length / 2 + button_corner_radius)
if requires_recoloring:
self._canvas.tag_raise("slider_parts")
return requires_recoloring
class CTkRangeSlider(CTkBaseClass):
"""
Range slider with rounded corners, border, number of steps, variable support, vertical orientation.

View File

@@ -1,4 +1,4 @@
// dd_ring_buffer.js
// buffer.js
// works kinda like an audio delay
// stacks the previous n frames into a buffer

View File

@@ -1,4 +1,4 @@
// dd_delay.js
// delay.js
// works kinda like an audio delay
// stacks the previous n frames into a buffer

View File

@@ -1,4 +1,4 @@
// dd_RandomDamage(invertRandomN).js
// invertReverse.js
// invert x and y component of mv for random number of frames if threshold met for frame
let threshold = 95;

View File

@@ -1,4 +1,4 @@
// dd_mirror_X.js
// mirror_X.js
// clean buffer :
var buffer = [ ];

View File

@@ -1,4 +1,4 @@
// dd_MultiplySlowest_50.js
// noise.js
// Multiply slowest moving mv's
var LARGEST = 0;
var SOME_PERCENTAGE = 0.5;

View File

@@ -1,4 +1,4 @@
// dd_sheer.js
// sheer.js
var ZOOM = -20;

View File

@@ -1,5 +1,5 @@
// dd_RandomDamage(antiGrav).js
// anitgravityify if threshold met for frame
// shift.js
// anitgravitify if threshold met for frame
let threshold = 98;
// global variable holding forward motion vectors from previous frames

View File

@@ -1,4 +1,4 @@
// dd_zero.js
// sink.js
// only mess frames if mv > movement_threshold
var movement_threshold = 3;
function glitch_frame(frame)

View File

@@ -1,4 +1,4 @@
// dd_slam_zoom_in.js
// slam_zoom.js
var ZOOM = 20;

View File

@@ -1,4 +1,4 @@
// dd_RandomDamage(progZoom).js
// slice.js
// progressive Zoom x and y components of mv if threshold met for frame
let threshold = 95;

View File

@@ -1,4 +1,4 @@
// dd_RandomDamage(stopXY).js
// stop.js
// stop x and y component of mv for n framesif threshold met for frame
let threshold = 95;

View File

@@ -1,4 +1,4 @@
// dd_zoom_in.js
// zoom.js
var ZOOM = 20;

View File

@@ -1,10 +1,10 @@
"""
DATAMOSHER PRO Py version 2.3
DATAMOSHER PRO Py version 2.4
Author: Akash Bora (Akascape)
License: MIT | Copyright (c) 2024 Akash Bora
License: MIT | Copyright (c) 2025 Akash Bora
"""
currentversion = 2.3
currentversion = 2.4
#Import installed modules
import tkinter
@@ -744,6 +744,14 @@ dynamic()
keepframe.select()
param = ""
def open_file(sfile):
if sys.platform.startswith('darwin'): # macOS
subprocess.call(('open', sfile))
elif os.name == 'nt': # Windows
os.startfile(sfile)
elif os.name == 'posix': # Linux
subprocess.call(('xdg-open', sfile))
#autosave video name
def savename():
global sfile
@@ -885,10 +893,10 @@ def do_the_mosh():
if os.path.exists(sfile):
res = messagebox.showinfo("Exported!", "File exported successfully, \nFile Location: " +str(sfile))
ProcessLabel.configure(text="Last used: "+last_used)
try: os.startfile(sfile)
try: open_file(sfile)
except: pass
else:
messagebox.showerror("Oops!", "Something went wrong! \nPlease recheck the settings and try again.")
messagebox.showerror("Oops!", "Something went wrong! \nPlease recheck the settings and try again.\nView error logs for more information.")
ProcessLabel.configure(text='Recheck the settings and try again!')
button_open.configure(state=tkinter.NORMAL)
@@ -904,6 +912,8 @@ button_mosh = customtkinter.CTkButton(master=frame_right, height=30,width=110,co
text="MOSH", command=Threadthis)
button_mosh.pack(padx=(0,10), pady=10, fill="x", side="right")
root.after(100, root.focus_force)
root.mainloop()
#--------------------------------------------------------------------#

View File

@@ -20,6 +20,27 @@ except ImportError:
DIRPATH = os.path.dirname(os.path.realpath(__file__))
#Set executable permissions for macOS
def set_mac_permissions():
if sys.platform.startswith("darwin"):
print("Setting executable permissions for macOS...")
ffgac = os.path.join(DIRPATH,"FFglitch","ffgac")
ffedit = os.path.join(DIRPATH,"FFglitch","ffedit")
try:
if os.path.exists(ffgac):
os.chmod(ffgac, 0o755)
print("Permissions set for ffgac")
except Exception as e:
print(f"Failed to set permissions for ffgac: {e} \nPlease go to System Settings -> Security & Privacy -> scroll down and give permission to the ffgac file")
try:
if os.path.exists(ffedit):
os.chmod(ffedit, 0o755)
print("Permissions set for ffedit")
except Exception as e:
print(f"Failed to set permissions for ffedit: {e} \nPlease go to System Settings -> Security & Privacy -> scroll down and give permission to the ffedit file")
#Checking the required folders
folders = ["Assets","FFglitch","DatamoshLib","pymosh"]
missingfolder=[]
@@ -69,6 +90,8 @@ else:
#Check FFglitch Status
def checkffglitch():
print("Checking FFglitch:")
# Set permissions for macOS before running
set_mac_permissions()
print("Running ffgac...")
ffgac = os.path.join(DIRPATH,"FFglitch","ffgac")
ffedit = os.path.join(DIRPATH,"FFglitch","ffedit")
@@ -130,6 +153,8 @@ else:
if os.path.exists(os.path.join("FFglitch","ffgac")) or os.path.exists(os.path.join("FFglitch","ffgac.exe")):
os.remove(os.path.join("FFglitch","ffglitch.zip"))
time.sleep(1)
set_mac_permissions()
checkffglitch()
print("FFglitch setup complete!")
except:
@@ -138,6 +163,8 @@ else:
print("ffglitch modes cannot run without ffgac and ffedit packages, download them manually and paste them inside the FFglitch folder.")
#Everything done!
time.sleep(1)
print("Setup Complete!")
time.sleep(5)
sys.exit()

View File

@@ -0,0 +1,7 @@
imageio
imageio-ffmpeg
numpy
customtkinter
pillow
requests
packaging

View File

@@ -18,7 +18,7 @@ Then I found some scripts and algorithms available for datamoshing which gives a
<br> <p align='center'> [<img src="https://custom-icon-badges.demolab.com/badge/WINDOWS/MAC-DATAMOSHER_PRO-informational?&logo=Datamosher_Pro&logoColor=blue&color=007ec6" width="500">](https://akascape.gumroad.com/l/Datamosher-Pro) </br>
### <p align='center'> FREE SOURCE CODE VERSION 🔻
<br> <p align='center'> [<img src="https://img.shields.io/badge/Python_Version-informational?style=flat&logo=python&logoColor=blue&color=eaea4a" width=300 height=50>](https://github.com/Akascape/Datamosher-Pro/releases/download/Datamosher_Prov2.3/Datamosher-Pro_python-version_2.3.zip) <br> Don't forget to leave a ⭐ </p>
<br> <p align='center'> [<img src="https://img.shields.io/badge/Python_Version-informational?style=flat&logo=python&logoColor=blue&color=eaea4a" width=300 height=50>](https://github.com/Akascape/Datamosher-Pro/releases/download/Datamosher_Prov2.4/Datamosher-Pro_python-version_2.4.zip) <br> Don't forget to leave a ⭐ </p>
# Installation? ⚙️
- For the premium version, just extract the downloaded zip file and run the "Datamosher Pro" application.
@@ -114,7 +114,7 @@ All the other required component licenses (mostly MIT) are provided in their fol
## DATAMOSH MADE EASY
| Current Python Version: | 2.3 |
| Current Python Version: | 2.4 |
| ----------------| --------- |
| Current Premium Version: | 2.8 |