Skip to content

Commit

Permalink
Merge pull request #16 from csgoh/dev-processpiper-0.4.1
Browse files Browse the repository at this point in the history
Dev processpiper 0.4.1
  • Loading branch information
csgoh authored Jun 23, 2023
2 parents f3e14b1 + 69d52ba commit 3d6d790
Show file tree
Hide file tree
Showing 45 changed files with 1,659 additions and 651 deletions.
Binary file added .pylintrc
Binary file not shown.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ Two frontend applications have been developed to showcase ProcessPiper capabilit
Please refer to [Processpiper Wiki](https://github.com/csgoh/processpiper/wiki) for more information on how to use this library.

## Examples
### (Method 1) Generate diagram using plain text
This is a sample code to generate a business process diagram using plain text.
### (Method 1) Generate diagram using English like PiperFlow syntax
This is a sample code to generate a business process diagram using PiperFlow syntax.
```python
from processpiper.text2diagram import render

Expand Down
Binary file modified images/test/test_auto_case1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case10-BLUEMOUNTAIN.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case10-DEFAULT.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case10-GREENTURTLE.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case10-GREYWOOF.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case10-ORANGEPEEL.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case14.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case15.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/test/test_case17.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/test/test_case9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ classifiers = [
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
dependencies = ['Pillow>=9.4.0']
dependencies = ['Pillow>=9.5.0']

[project.urls]
"Homepage" = "https://github.com/csgoh/processpiper"
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Pillow==9.5.0
pytest==7.2.2
pytest==7.3.2
10 changes: 4 additions & 6 deletions src/processpiper/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,14 @@
class Activity(Box):
"""Represents an activity types in a process flow diagram."""

...


class Task(Activity):
"""A task is a special type of activity that is represented by a box."""

...


class Subprocess(Activity):
"""A subprocess is a special type of activity that is represented by a box with a plus sign in it."""
"""A subprocess is a special type of activity that
is represented by a box with a plus sign in it."""

def draw(self, painter: Painter):
super().draw(painter)
Expand All @@ -63,4 +60,5 @@ def draw(self, painter: Painter):
raise NotImplementedError("ServiceTask is not implemented yet.")


### To implement: User Task,Script Task,Business Rule Task, Manual Task, Received Task,Send Task, Receive Task
### To implement: User Task,Script Task,Business Rule Task,
# Manual Task, Received Task,Send Task, Receive Task
5 changes: 3 additions & 2 deletions src/processpiper/colourtheme.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,14 +297,15 @@ class ColourTheme:
"""Colour theme for the ProcessPiper."""

def __init__(self, colour_theme_name: str) -> None:
# sourcery skip: simplify-boolean-comparison, use-any
"""Initialise the colour theme."""

found = False
for theme in ColourThemesSettings:
if theme["theme"] == colour_theme_name:
found = True

if found == False:
if found is False:
raise ValueError(f"Colour theme {colour_theme_name} not recognised.")

self._colour_theme_name = colour_theme_name
Expand All @@ -314,7 +315,7 @@ def get_colour_theme_settings(self, processmap_component: str) -> tuple:

colour_settings = None

for _, value in enumerate(ColourThemesSettings):
for value in ColourThemesSettings:
if value["theme"] == self._colour_theme_name:
colour_settings = value["settings"]
break
Expand Down
8 changes: 7 additions & 1 deletion src/processpiper/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,16 @@ class Configs:
LANE_SHAPE_LEFT_MARGIN = 50
LANE_SHAPE_RIGHT_MARGIN = 30

HSPACE_BETWEEN_SHAPES = 50
HSPACE_BETWEEN_SHAPES = 80
VSPACE_BETWEEN_SHAPES = 100

VSPACE_BETWEEN_POOLS = 10
VSPACE_BETWEEN_LANES = 2

HSPACE_BETWEEN_POOL_AND_LANE = 2

BOX_WIDTH = 100
BOX_HEIGHT = 60
CIRCLE_RADIUS = 20
DIAMOND_WIDTH = 40
DIAMOND_HEIGHT = DIAMOND_WIDTH
12 changes: 4 additions & 8 deletions src/processpiper/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,10 @@ def draw_stop_circle(painter: Painter, x_pos: int, y_pos: int, radius: int):
class Event(Circle):
"""Event class for representing events in a process."""

...


class Start(Event):
"""Start event class for representing start event in a process."""

...


class End(Event):
"""End event class for representing end event in a process."""
Expand Down Expand Up @@ -168,10 +164,10 @@ def draw(self, painter: Painter):
circle_center[0] - envelope_width // 2,
circle_center[1] - envelope_height // 2,
)
envelope_bottom_right = (
circle_center[0] + envelope_width // 2,
circle_center[1] + envelope_height // 2,
)
# envelope_bottom_right = (
# circle_center[0] + envelope_width // 2,
# circle_center[1] + envelope_height // 2,
# )

painter.draw_box_with_outline(
envelope_top_left[0],
Expand Down
35 changes: 32 additions & 3 deletions src/processpiper/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,43 @@


class Helper:
show_layout_grid = False
show_pool_lane = False
show_x_position = False
show_y_position = False
show_draw_position = False
show_draw_connection = False
show_draw = False
show_general = False

@staticmethod
def printc(
message: str, color: str = "30", end: str = "\n", show_level: str = "general"
):
"""Print text in color"""

root_logger = logging.getLogger()

if root_logger.getEffectiveLevel() == logging.DEBUG and (
(show_level == "layout_grid" and Helper.show_layout_grid)
or (show_level == "pool_lane" and Helper.show_pool_lane)
or (show_level == "x_position" and Helper.show_x_position)
or (show_level == "y_position" and Helper.show_y_position)
or (show_level == "draw_connection" and Helper.show_draw_connection)
or (show_level == "draw_position" and Helper.show_draw_position)
or (show_level == "draw" and Helper.show_draw)
or (show_level == "general" and Helper.show_general)
):
print(f"\033[1;{color}m{message}\033[0m", end=end)

@staticmethod
def printc(message: str, color: str = "30"):
def print_info(message: str, color: str = "30", end: str = "\n"):
"""Print text in color"""

root_logger = logging.getLogger()

if root_logger.getEffectiveLevel() == logging.DEBUG:
print(f"\033[1;{color}m{message}\033[0m")
if root_logger.getEffectiveLevel() == logging.INFO:
print(f"\033[1;{color}m{message}\033[0m", end=end)

@staticmethod
def debug_log(message: str):
Expand Down
155 changes: 47 additions & 108 deletions src/processpiper/lane.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from .gateway import *
from .constants import Configs
from .helper import Helper
from .layout import Grid

# from .helper import Helper

Expand Down Expand Up @@ -165,31 +166,6 @@ def __enter__(self):
def __exit__(self, exc_type, exc_value, traceback) -> None:
pass

def get_current_y_position(self) -> int:
"""Get the current y position of the lane"""
if self.shape_row_count == 0:
self.shape_row_count = 1
if self.next_shape_y == 0:
self.next_shape_y = self.y + Configs.LANE_SHAPE_TOP_MARGIN

return self.next_shape_y

def get_next_y_position(self) -> int:
"""Get the next y position of the lane"""

if self.next_shape_y == 0:
# self.next_shape_y = self.y + 60 + Configs.LANE_SHAPE_TOP_MARGIN
self.next_shape_y = self.y + Configs.LANE_SHAPE_TOP_MARGIN
else:
self.next_shape_y += 60 + Configs.VSPACE_BETWEEN_SHAPES

### For every method call, increment the shape row count
if self.shape_row_count == 0:
self.shape_row_count = 1
else:
self.shape_row_count += 1
return self.next_shape_y

def draw(self) -> None:
"""Draw the lane"""

Expand Down Expand Up @@ -233,100 +209,63 @@ def draw_shape(self) -> None:
if self.shapes:
for shape in self.shapes:
Helper.printc(
f"Drawing shape: {shape.name}, x={shape.x}, y={shape.y}, w={shape.width}, h={shape.height}"
f" Drawing shape: {shape.name}, x={shape.x}, y={shape.y}, w={shape.width}, h={shape.height}",
show_level="draw",
)
shape.draw(self.painter)

def draw_connection(self) -> None:
def draw_connection(self, all_shapes: list) -> None:
"""Draw the connections in the lane"""
if self.shapes:
for shape in self.shapes:
shape.draw_connection(self.painter)
shape.draw_connection(self.painter, all_shapes)

def set_draw_position(self, x: int, y: int, painter: Painter) -> None:
def set_draw_position(self, x: int, y: int, layout_grid: Grid) -> None:
"""Set the draw position of the lane"""

self.painter = painter
# self.painter = painter

### Determine the number of rows for the lane
lane_row_count = layout_grid.get_lane_row_count(self.id)

### Determine the x and y position of the lane
### If x and y are not specified, add the default margin
self.x = x if x > 0 else Configs.SURFACE_LEFT_MARGIN + Configs.POOL_TEXT_WIDTH
### Determine lane x and y position
self.x = (
x
if x > 0
else Configs.SURFACE_LEFT_MARGIN
+ Configs.POOL_TEXT_WIDTH
+ Configs.HSPACE_BETWEEN_POOL_AND_LANE
)
self.y = y if y > 0 else Configs.SURFACE_TOP_MARGIN

if self.shapes:
self.next_shape_x = (
self.x
+ Configs.POOL_TEXT_WIDTH
+ Configs.LANE_TEXT_WIDTH
+ Configs.LANE_SHAPE_LEFT_MARGIN
)

shape_x, shape_y, shape_w, shape_h = self.set_shape_draw_position(
self.next_shape_x, self.y, self.shapes[0], painter
)

self.width = max(self.width, shape_x + shape_w)
self.height = max(
self.height,
shape_y + shape_h - self.y + Configs.LANE_SHAPE_BOTTOM_MARGIN,
)

self.next_shape_x = shape_x + shape_w + Configs.HSPACE_BETWEEN_SHAPES

return self.x, self.y, self.width, self.height

def set_shape_draw_position(
self, x: int, y: int, shape: Shape, painter: Painter
) -> None:
"""Set the draw position of the shapes in the lane"""
### Set own shape position
if shape.lane_name == self.name:
shape_x, shape_y, shape_w, shape_h = shape.set_draw_position(
x,
(y + Configs.LANE_SHAPE_TOP_MARGIN),
painter,
)

#### Mark for removal
# shape.draw_position_set = True

shape.x_pos_traversed = True

### Set next elements' position
for index, next_shape in enumerate(shape.connection_to.target):
### Check whether the position has been set, if yes, skipped.
### This is needed to avoid infinite recursion
if next_shape.traversed == True:
continue

if index == 0:
next_shape_y = y
else:
next_shape_y = (
y
+ Configs.LANE_SHAPE_TOP_MARGIN
+ Configs.HSPACE_BETWEEN_SHAPES
+ shape_h
)

### Perform recursive call to set the position of the next element
(
next_shape_x,
next_shape_y,
next_shape_w,
next_shape_h,
) = self.set_shape_draw_position(
self.next_shape_x, next_shape_y, next_shape, painter
)
### Determine lane width
max_column_count = layout_grid.get_max_column_count()
Helper.printc(
f"~~~ max column count: {max_column_count}", show_level="pool_lane"
)
self.width = (
(Configs.HSPACE_BETWEEN_SHAPES * max_column_count - 1)
+ (Configs.BOX_WIDTH * max_column_count)
+ (Configs.LANE_SHAPE_LEFT_MARGIN)
)

shape_x, shape_y, shape_w, shape_h = (
max(shape_x, next_shape_x),
max(shape_y, next_shape_y),
max(shape_w, next_shape_w),
max(shape_h, next_shape_h),
)
self.next_shape_x = next_shape_x
else:
shape_x, shape_y, shape_w, shape_h = 0, 0, 0, 0
Helper.printc(
f"~~~ Lane: [{self.name}] shape row count: {lane_row_count}",
35,
show_level="pool_lane",
)

### Determine lane height
self.height = (
(lane_row_count * 60)
+ ((lane_row_count - 1) * Configs.VSPACE_BETWEEN_SHAPES)
+ Configs.LANE_SHAPE_TOP_MARGIN
+ Configs.LANE_SHAPE_BOTTOM_MARGIN
)
Helper.printc(
f"~~~ [{self.name}] {self.x=}, {self.y=}, {self.width=}, {self.height=}",
show_level="pool_lane",
)
y_pos = self.y + self.height + Configs.VSPACE_BETWEEN_LANES

return shape_x, shape_y, shape_w, shape_h
return self.x, y_pos, self.width, self.height
Loading

0 comments on commit 3d6d790

Please sign in to comment.