Skip to content

Commit

Permalink
Merge pull request #73 from cmang/dev
Browse files Browse the repository at this point in the history
Dev -> Main merge
  • Loading branch information
cmang authored Oct 19, 2024
2 parents 652b287 + 0e30fc6 commit 30ed587
Show file tree
Hide file tree
Showing 27 changed files with 1,650 additions and 460 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ That's awesome that you want to help! I thank you. The guidelines are pretty loo

* If you want to help "clean up" the code to make it more legible or modular, that's great. But, I request that you let me see some of the style changes you are proposing before you dump a giant patch of changes. I don't want major changes in a style I don't enjoy.

* Use Git and Github for development, discussion, pull requests, issues, proposals, etc. You can also contact the developer directly via email (see README.md CREDITS), or try the #durdraw IRC channel on irc.libera.chat.
* Use Git and Github for development, discussion, pull requests, issues, proposals, etc. You can also contact the developer directly via email (see README.md CREDITS), or you can find us on Discord or IRC (see README.md for details).

* If you want to contribute ANSI or ASCII Art, that's great! Please post it in the Discussions on Github and give consent if you are OK with it being used (in the program, website, Readme file, youtube videos, etc).

Expand Down
269 changes: 198 additions & 71 deletions README.md

Large diffs are not rendered by default.

25 changes: 24 additions & 1 deletion durdraw.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
; Durdraw 0.20.0 Configuration File
; Durdraw 0.28.0 Configuration File

[Main]
; color-mode sets the color mode to start in. Available options: 16, 256
;color-mode: 16

; disable-mouse.. disablse the mouse.
;disable-mouse: True

; max-canvas atuomatically sets the canvas size to the terminal window size at startup.
;max-canvas: True

; Cursor mode requests a cursor type from the terminal. Available options: block, underscore, pipe
;cursor-mode: underscore

; When scroll-colors is enabled, using the mouse wheel in the canvas changes the
; foreground color instead of moving the cursor.
;scroll-colors: True

[Theme]
; theme-16: ~/.durdraw/themes/purpledrank-16.dtheme.ini
theme-16: ~/.durdraw/themes/mutedchill-16.dtheme.ini
theme-256: ~/.durdraw/themes/mutedform-256.dtheme.ini

;[Charset]
;charset-file-utf8: durdraw/charsets/unicode-legacy-computing.json
;charset-file-cp437: durdraw/charsets/cp437-ibmpc.json

11 changes: 6 additions & 5 deletions durdraw/durdraw_ansiparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,18 +185,19 @@ def parse_ansi_escape_codes(text, filename = None, appState=None, caller=None, c
#if sauce.height == None:
# sauce.height = 25
if sauce.width == None:
sauce.width = 80
#sauce.width = 80
sauce.width = maxWidth
maxWidth = sauce.width
width = sauce.width
height = sauce.height
#caller.notify(f"Sauce pulled: author: {sauce.author}, title: {sauce.title}, width {width}, height {height}")
if not sauce.height:
width, height = get_width_and_height_of_ansi_blob(text, width=80)
width, height = get_width_and_height_of_ansi_blob(text)
width = sauce.width
if not sauce.sauce_found or width > 200 or height > 1200: # let the dodgy function guess
width, height = get_width_and_height_of_ansi_blob(text, width=80)
#width = max(width, maxWidth)
width = max(width, 80)
width, height = get_width_and_height_of_ansi_blob(text)
width = max(width, maxWidth)
#width = max(width, 80)
height += 1
if appState.debug:
caller.notify(f"Guessed width: {width}, height: {height}")
Expand Down
113 changes: 100 additions & 13 deletions durdraw/durdraw_appstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,41 @@
import pickle
import subprocess
import sys
import threading
from sys import version_info
from durdraw.durdraw_options import Options
import durdraw.durdraw_file as durfile
import durdraw.durdraw_sauce as dursauce

class AppState():
""" run-time app state, separate from movie options (Options()) """
def __init__(self): # User friendly defeaults
def __init__(self):

# Check for optional dependencies
#self.ansiLove = self.isAppAvail("ansilove")
#self.neofetch = self.isAppAvail("neofetch")
#self.PIL = self.checkForPIL()

self.ansiLove = None
self.neofetch = None
self.PIL = None
self.check_dependencies()

# User friendly defeaults
self.quickStart = False
self.showStartupScreen = True
self.mental = False # Mental mode - enable experimental options/features
self.showStartupScreen = False
self.narrowWindow = False
self.curOpenFileName = ""
python_version = f"{version_info.major}.{version_info.minor}.{version_info.micro}"
self.pyVersion = python_version
self.colorMode = "256" # or 16, or possibly "none" or "true" or "rgb" (24 bit rgb "truecolor")
self.fileColorMode = None
self.maxColors = 256
self.iceColors = False
self.can_inject = False # Allow injecting color codes to override ncurses colors (for BG 256 colors)
self.showBgColorPicker = False # until BG colors work in 256 color mode. (ncurses 5 color pair limits)
self.scrollColors = False # When true, scroll wheel in canvas changes color instead of moving cursor
self.editorRunning = True
self.screenCursorMode = "default" # can be block, underscore, pipe
self.renderMouseCursor = False # show Paint or Draw cursor in canvas
Expand All @@ -31,6 +50,11 @@ def __init__(self): # User friendly defeaults
self.totalBgColors = 8
self.defaultFgColor = 7
self.defaultBgColor = 0
self.width = 80 # default canvas width/columns
self.height = 23 # default canvas height/lines
self.wrapWidth = 80 # Default width to wrap at when loading ASCII files (.asc/.txt)
self.minWindowWidth = 40 # smaller than this, and Durdraw complains that it can't draw the UI
self.full_ui_width = 80 # smaller than this, and draw the streamlined UI
self.stickyColorPicker = True # true to keep color picker on screen
self.colorPickerSelected = False # true when the user hits esc-c
self.charEncoding = 'utf-8' # or cp437, aka ibm-pc
Expand All @@ -45,11 +69,13 @@ def __init__(self): # User friendly defeaults
#self.characterSet = "Unicode Block"
self.unicodeBlock = "Braille Patterns" # placeholder during initialization
self.cursorMode = "Move" # Move/Select, Draw and Color
self.fetchMode = False # use neofetch, replace {variables} in dur file
self.fetchData = None # a {} dict containing key:value for neofetch output.
self.inferno = None
self.inferno_opts = None
self.playOnlyMode = False # This means viewer mode now, actually..
self.viewModeShowInfo = False # show sauce etc in view mode
self.playNumberOfTimes = 0 # 0 = loop forever, default
self.ansiLove = self.isAppAvail("ansilove")
self.PIL = self.checkForPIL()
self.undoHistorySize = 100 # How far back our undo history can
self.playbackRange = (1,1)
self.drawChar = '$'
Expand Down Expand Up @@ -81,7 +107,6 @@ def __init__(self): # User friendly defeaults
self.durhelp256_page2_fullpath = None
self.durhelp16_fullpath = None
self.durhelp16_page2_fullpath = None
self.showBgColorPicker = False # until BG colors work in 256 color mode. (ncurses 5 color pair limits)
# This doesn't work yet (color pairs past 256 colors. They set, but the background color doesn't get set.
#if sys.version_info >= (3, 10):
# if curses.has_extended_color_support(): # Requires Ncures 6
Expand Down Expand Up @@ -132,6 +157,23 @@ def __init__(self): # User friendly defeaults
}
self.theme = self.theme_16

def maximize_canvas(self):
term_size = os.get_terminal_size()
if term_size[0] > 80:
self.width = term_size[0]
if term_size[1] > 24:
self.height = term_size[1] - 2

def check_dependencies(self):
dependency_thread = threading.Thread(target=self.thread_check_dependencies)
dependency_thread.start()

def thread_check_dependencies(self):
# Check for optional dependencies
self.ansiLove = self.isAppAvail("ansilove")
self.neofetch = self.isAppAvail("neofetch")
self.PIL = self.checkForPIL()

def setCursorModeMove(self):
self.cursorMode="Move"

Expand Down Expand Up @@ -162,6 +204,19 @@ def setDurVer(self, version):
def setDebug(self, isEnabled: bool):
self.debug = isEnabled

def loadThemeList(self):
""" Look for theme files in internal durdraw directory """
# durhelp256_fullpath = pathlib.Path(__file__).parent.joinpath("help/durhelp-256-long.dur")
# Get a list of files from the themes paths
internal_theme_path = pathlib.Path(__file__).parent.joinpath("themes/")
self.internal_theme_file_list = glob.glob(f"{internal_theme_path}/*.dtheme.ini")
#user_theme_path = pathlib.Path(__file__).parent.joinpath("themes/")
#self.user_theme_file_list = glob.glob(f"{user_theme_path}/*.dtheme.ini")
# Turn lists into an index of Theme name, Theme type, and Path to
available_themes = [] # populate with a list of dicts containing name=, path=, type=
for filename in self.internal_theme_file_list:
pass

def loadConfigFile(self):
# Load configuration filea
configFullPath = os.path.expanduser("~/.durdraw/durdraw.ini")
Expand All @@ -188,15 +243,15 @@ def loadThemeFromConfig(self, themeMode):
self.loadThemeFile(themeConfig['theme-16'], themeMode)
if 'theme-256' in themeConfig and themeMode == 'Theme-256':
self.loadThemeFile(themeConfig['theme-256'], themeMode)


def loadThemeList(self):
""" Look for theme files in internal durdraw directory """
# durhelp256_fullpath = pathlib.Path(__file__).parent.joinpath("help/durhelp-256-long.dur")
# Get a list of files from the themes paths
internal_theme_path = pathlib.Path(__file__).parent.joinpath("themes/")
internal_theme_file_list = glob.glob(f"{internal_theme_path}/*.dtheme.ini")
pass
def getConfigOption(self, section: str, item: str):
# section = something like [Main], item = something like color-mode:
try: # see if section and item exist, otherwise return False
configSection = self.configFile[section]
configItem = configSection[item]
return configItem
except KeyError:
return False

def loadThemeFile(self, themeFilePath, themeMode):
# If there is a theme set, use it
Expand Down Expand Up @@ -250,6 +305,38 @@ def isAppAvail(self, name): # looks for program 'name' in path
return False
return True

def loadDurFileToMov(self, fileName):
""" Takes a file path, returns a movie object """
fileName = os.path.expanduser(fileName)
#self.helpMov = Movie(self.opts) # initialize a new movie to work with
try:
f = open(fileName, 'rb')
except Exception as e:
return False
if (f.read(2) == b'\x1f\x8b'): # gzip magic number
# file == gzip compressed
f.close()
try:
f = gzip.open(fileName, 'rb')
except Exception as e:
return False
else:
f.seek(0)
try: # Load json help file
#pdb.set_trace()
loadedContainer = durfile.open_json_dur_file(f, self)
opts = loadedContainer['opts']
mov = loadedContainer['mov']
return mov, opts
except:
#pass # loading json help file failed for some reason, so...
return False


def loadHelpFileThread(self, helpFileName):
help_loading_thread = threading.Thread(target=self.loadHelpFile, args=(helpFileName,))
help_loading_thread.start()

def loadHelpFile(self, helpFileName, page=1):
helpFileName = os.path.expanduser(helpFileName)
#self.helpMov = Movie(self.opts) # initialize a new movie to work with
Expand Down
6 changes: 3 additions & 3 deletions durdraw/durdraw_color_curses.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,9 @@ def getColorCode256(self, fg, bg):
fg = color_256_to_ansi_16[fg]
code = '\033[38;5;' # begin escape sequence
code = code + str(fg)
#code = code + ';'
#code = code + '48;5;'
#code = code + str(bg)
code = code + ';'
code = code + '48;5;'
code = code + str(bg)
#code = code + str('0')
code = code + 'm'
return code
Expand Down
3 changes: 2 additions & 1 deletion durdraw/durdraw_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ def open_json_dur_file(f, appState):
currentFrame = 0
lineNum = 0
for frame in loadedMovieData['DurMovie']['frames']:
newMov.insertCloneFrame()
#newMov.insertCloneFrame()
newMov.addEmptyFrame()
newMov.nextFrame()
for line in frame['contents']:
#pdb.set_trace()
Expand Down
65 changes: 63 additions & 2 deletions durdraw/durdraw_movie.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,11 @@ class Movie():
def __init__(self, opts):
self.frameCount = 0 # total number of frames
self.currentFrameNumber = 0
self.sizeX = opts.sizeX
self.sizeY = opts.sizeY
self.sizeX = opts.sizeX # Number of columns
self.sizeY = opts.sizeY # Number of lines
self.opts = opts
self.frames = []
self.layers = {} # Key can be a layer #, or something special. eg: "masks
self.addEmptyFrame()
self.currentFrameNumber = self.frameCount
self.currentFrame = self.frames[self.currentFrameNumber - 1]
Expand Down Expand Up @@ -208,6 +209,12 @@ def prevFrame(self):
self.currentFrameNumber -= 1
self.currentFrame = self.frames[self.currentFrameNumber - 1]

def hasMultipleFrames(self):
if len(self.frames) > 1:
return True
else:
return False

def growCanvasWidth(self, growth):
self.sizeX += growth
self.opts.sizeX += growth
Expand All @@ -218,6 +225,41 @@ def shrinkCanvasWidth(self, shrinkage):
self.opts.sizeY = self.opts.sizeY - shrinkage
#self.width = self.width - shrinkage

def search_and_replace_color_pair(self, old_color, new_color, frange=None):
if frange != None: # apply to all frames in range
for frameNum in range(frange[0] - 1, frange[1]):
#for frame in self.frames:
frame = self.frames[frameNum]
line_num = 0
col_num = 0
for line in frame.newColorMap:
for pair in line:
if pair == old_color:
try:
frame.newColorMap[line_num][col_num] = new_color
except:
pdb.set_trace()
#found = True
col_num += 1
line_num += 1
col_num = 0
else: # only apply to current frame
frame = self.currentFrame
line_num = 0
col_num = 0
for line in frame.newColorMap:
for pair in line:
if pair == old_color:
try:
frame.newColorMap[line_num][col_num] = new_color
except:
pdb.set_trace()
#found = True
col_num += 1
line_num += 1
col_num = 0


def search_and_replace_color(self, old_color :int, new_color :int):
found = False
for frame in self.frames:
Expand Down Expand Up @@ -386,6 +428,25 @@ def strip_backgrounds(self):
pair[1] = 0
return True

def strip_unprintable_characters(self):
""" Remove all non-printable characters from canvas """
#frame_num = 0
for frame in self.frames:
line_num = 0
col_num = 0
for line in frame.content:
for char in line:
if char.isprintable():
pass
else: # Not a printable character, so replace it with a ' '
#line_str = line_str.replace(search_str, replace_str.ljust(len(search_str)))
#line = list(line_str)
frame.content[line_num][col_num] = ' '
col_num += 1
col_num = 0
line_num += 1
return True

def shift_right(self):
""" Shift all frames to the right, wrapping the last frame back to the front """
# a.insert(0,a.pop())
Expand Down
3 changes: 3 additions & 0 deletions durdraw/durdraw_sauce.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ def __init__(self):
self.fileType_offset = 95
self.tinfo1_offset = 96
self.tinfo2_offset = 98
# Number of lines in the extra SAUCE comment block. 1 byte. 0 indicates no comment block is present.
self.comnt_lines = 105
self.comnt_first_line = 133 # comment lines are 64 bytes long

# other stuff
self.sauce_blob = None
Expand Down
Loading

0 comments on commit 30ed587

Please sign in to comment.