284 lines
12 KiB
Python
284 lines
12 KiB
Python
#!/usr/bin/env python3
|
||
"""Folie 3 – LIS mit Umsystemen (Adapter, links/rechts) und andockenden Modulen
|
||
(unten), unter einer Steuerungs-/Governance-Schicht; weitere LIS angedeutet."""
|
||
|
||
import os
|
||
from pptx import Presentation
|
||
from pptx.util import Inches, Pt
|
||
from pptx.dml.color import RGBColor
|
||
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
|
||
from pptx.enum.shapes import MSO_SHAPE
|
||
from adesso_style import (WHITE, INK, BLUE, TEAL, GREEN, CORAL, LIGHT, MUTE, RECF,
|
||
F, FC, paint_background, chrome)
|
||
|
||
# Rollen-Mapping auf die adesso-Palette
|
||
NAVY = INK # dunkle Strukturelemente (Bar, LIS-Kern)
|
||
ACCENT = CORAL # Adapter-Linien
|
||
AMBER = GREEN # zweites Modul
|
||
LINEC = LIGHT # Verbinder / feine Linien
|
||
HINT = RGBColor(0xE6, 0xEF, 0xF8) # helle "weitere LIS"-Karten
|
||
HINTL = RGBColor(0xC4, 0xD6, 0xE8)
|
||
TINT_T = WHITE # Modul-Boxen weiß
|
||
TINT_A = WHITE
|
||
UMS = WHITE # Umsystem-Boxen weiß
|
||
BG = WHITE
|
||
|
||
prs = Presentation()
|
||
prs.slide_width = Inches(13.333)
|
||
prs.slide_height = Inches(7.5)
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
paint_background(s, prs.slide_width, prs.slide_height)
|
||
|
||
|
||
def shp(kind, x, y, w, h, fill=None, line=None, lw=Pt(1), rot=0):
|
||
sh = s.shapes.add_shape(kind, x, y, w, h)
|
||
if fill is None: sh.fill.background()
|
||
else: sh.fill.solid(); sh.fill.fore_color.rgb = fill
|
||
if line is None: sh.line.fill.background()
|
||
else: sh.line.color.rgb = line; sh.line.width = lw
|
||
if rot: sh.rotation = rot
|
||
sh.shadow.inherit = False
|
||
return sh
|
||
|
||
|
||
def boxtext(sh, t, size=14, color=INK, bold=False):
|
||
tf = sh.text_frame; tf.word_wrap = True
|
||
tf.vertical_anchor = MSO_ANCHOR.MIDDLE
|
||
tf.margin_left = tf.margin_right = Pt(3); tf.margin_top = tf.margin_bottom = Pt(1)
|
||
p = tf.paragraphs[0]; p.alignment = PP_ALIGN.CENTER
|
||
r = p.add_run(); r.text = t
|
||
r.font.size = Pt(size); r.font.bold = bold; r.font.name = F; r.font.color.rgb = color
|
||
|
||
|
||
def txt(x, y, w, h, t, size=14, color=INK, bold=False, italic=False,
|
||
align=PP_ALIGN.LEFT, spc=None):
|
||
tb = s.shapes.add_textbox(x, y, w, h); tf = tb.text_frame
|
||
tf.word_wrap = True; tf.vertical_anchor = MSO_ANCHOR.MIDDLE
|
||
tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = Pt(0)
|
||
p = tf.paragraphs[0]; p.alignment = align
|
||
r = p.add_run(); r.text = t
|
||
r.font.size = Pt(size); r.font.bold = bold; r.font.italic = italic
|
||
r.font.name = F; r.font.color.rgb = color
|
||
if spc: r.font._rPr.set('spc', str(spc))
|
||
return tb
|
||
|
||
|
||
def hline(x, y, w, color=LINEC, weight=Pt(1.4)):
|
||
shp(MSO_SHAPE.RECTANGLE, x, y - weight / 2, w, weight, fill=color)
|
||
|
||
|
||
def vline(x, y, h, color=LINEC, weight=Pt(1.4)):
|
||
shp(MSO_SHAPE.RECTANGLE, x - weight / 2, y, weight, h, fill=color)
|
||
|
||
|
||
# ---- Kopf ------------------------------------------------------------------
|
||
chrome(s, "Offen – und gesteuert", 3)
|
||
|
||
x0, x1 = Inches(0.95), Inches(12.38)
|
||
|
||
|
||
# ===========================================================================
|
||
# GOVERNANCE – Icon-Karten + Strich
|
||
# ===========================================================================
|
||
def card(cx, label):
|
||
cw_, ch_ = Inches(2.05), Inches(1.25)
|
||
x, y = cx - cw_ / 2, Inches(1.5)
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, cw_, ch_, fill=BG, line=LINEC, lw=Pt(1.25))
|
||
txt(x, y + ch_ - Inches(0.4), cw_, Inches(0.34), label,
|
||
size=14, color=NAVY, bold=True, align=PP_ALIGN.CENTER)
|
||
return cx, y + Inches(0.42)
|
||
|
||
|
||
def regler(cx, cy):
|
||
tw = Inches(0.62)
|
||
left = cx - tw / 2
|
||
for j, frac in enumerate([0.30, 0.68, 0.48]):
|
||
ty = cy - Inches(0.18) + j * Inches(0.18)
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, left, ty - Inches(0.022), tw, Inches(0.045), fill=LINEC)
|
||
kx = left + Inches(0.62 * frac)
|
||
shp(MSO_SHAPE.OVAL, kx - Inches(0.07), ty - Inches(0.07),
|
||
Inches(0.14), Inches(0.14), fill=NAVY)
|
||
|
||
|
||
cx1, cy1 = card(Inches(4.75), "Steuerung")
|
||
cx2, cy2 = card(Inches(6.95), "Reporting")
|
||
cx3, cy3 = card(Inches(9.15), "Governance")
|
||
|
||
regler(cx1, cy1)
|
||
|
||
# Reporting – Zahlenreihen
|
||
nb = s.shapes.add_textbox(cx2 - Inches(0.85), cy2 - Inches(0.36), Inches(1.7), Inches(0.72))
|
||
tf = nb.text_frame; tf.word_wrap = False; tf.vertical_anchor = MSO_ANCHOR.MIDDLE
|
||
tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = Pt(0)
|
||
for i, row in enumerate(["3 8 1 4 7", "6 0 9 2 5", "5 7 2 8 1"]):
|
||
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
|
||
p.alignment = PP_ALIGN.CENTER; p.line_spacing = 0.95
|
||
r = p.add_run(); r.text = row
|
||
r.font.size = Pt(11); r.font.name = "Consolas"; r.font.color.rgb = MUTE
|
||
|
||
# Governance – §
|
||
gtb = s.shapes.add_textbox(cx3 - Inches(0.6), cy3 - Inches(0.42), Inches(1.2), Inches(0.8))
|
||
gtf = gtb.text_frame; gtf.vertical_anchor = MSO_ANCHOR.MIDDLE
|
||
gp = gtf.paragraphs[0]; gp.alignment = PP_ALIGN.CENTER
|
||
gr = gp.add_run(); gr.text = "§"; gr.font.size = Pt(34); gr.font.bold = True
|
||
gr.font.name = F; gr.font.color.rgb = NAVY
|
||
|
||
gov_y = Inches(3.05)
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x0, gov_y - Inches(0.07), x1 - x0, Inches(0.14), fill=NAVY)
|
||
for cc in (cx1, cx2, cx3):
|
||
vline(cc, Inches(2.75), gov_y - Inches(0.07) - Inches(2.75), color=LINEC, weight=Pt(1))
|
||
|
||
|
||
# ===========================================================================
|
||
# LIS + Umsysteme (Adapter links/rechts) + Module (andocken, unten)
|
||
# ===========================================================================
|
||
core_x, core_w = Inches(3.7), Inches(2.3)
|
||
core_y, core_h = Inches(4.3), Inches(1.2)
|
||
core_cx = core_x + core_w / 2
|
||
core_by = core_y + core_h
|
||
|
||
# Adapter-Schicht: echte Schicht als Hülle um den Kern (Trennung)
|
||
lay_pad_x, lay_pad_t = Inches(0.24), Inches(0.30)
|
||
lay_x = core_x - lay_pad_x
|
||
lay_w = core_w + lay_pad_x * 2
|
||
lay_y = core_y - lay_pad_t
|
||
lay_h = core_h + lay_pad_t
|
||
lay_right = lay_x + lay_w
|
||
|
||
|
||
def adapter(xc, yc):
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, xc - Inches(0.10), yc - Inches(0.11),
|
||
Inches(0.16), Inches(0.22), fill=ACCENT)
|
||
shp(MSO_SHAPE.RECTANGLE, xc + Inches(0.06), yc - Inches(0.055), Inches(0.1), Pt(2.4), fill=ACCENT)
|
||
shp(MSO_SHAPE.RECTANGLE, xc + Inches(0.06), yc + Inches(0.03), Inches(0.1), Pt(2.4), fill=ACCENT)
|
||
|
||
|
||
def dock(xc, yc):
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, xc - Inches(0.1), yc - Inches(0.1),
|
||
Inches(0.2), Inches(0.2), fill=NAVY)
|
||
shp(MSO_SHAPE.OVAL, xc - Inches(0.055), yc - Inches(0.055), Inches(0.11), Inches(0.11),
|
||
fill=ACCENT)
|
||
|
||
|
||
def icon_truck(ix, iy): # Anlieferung
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, ix - Inches(0.20), iy - Inches(0.10),
|
||
Inches(0.24), Inches(0.16), fill=NAVY)
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, ix + Inches(0.05), iy - Inches(0.035),
|
||
Inches(0.12), Inches(0.095), fill=NAVY)
|
||
for wx in (ix - Inches(0.11), ix + Inches(0.08)):
|
||
shp(MSO_SHAPE.OVAL, wx - Inches(0.038), iy + Inches(0.05),
|
||
Inches(0.076), Inches(0.076), fill=NAVY)
|
||
|
||
|
||
def icon_device(ix, iy): # Gerät
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, ix - Inches(0.16), iy - Inches(0.14),
|
||
Inches(0.32), Inches(0.28), fill=NAVY)
|
||
shp(MSO_SHAPE.RECTANGLE, ix - Inches(0.11), iy - Inches(0.10),
|
||
Inches(0.22), Inches(0.085), fill=RGBColor(0x34, 0x4E, 0x70))
|
||
shp(MSO_SHAPE.OVAL, ix - Inches(0.085), iy + Inches(0.03), Inches(0.055), Inches(0.055), fill=TEAL)
|
||
shp(MSO_SHAPE.OVAL, ix + Inches(0.03), iy + Inches(0.03), Inches(0.055), Inches(0.055), fill=AMBER)
|
||
|
||
|
||
def icon_dfu(ix, iy): # DFÜ
|
||
shp(MSO_SHAPE.RIGHT_ARROW, ix - Inches(0.16), iy - Inches(0.12), Inches(0.32), Inches(0.095),
|
||
fill=NAVY)
|
||
shp(MSO_SHAPE.LEFT_ARROW, ix - Inches(0.16), iy + Inches(0.025), Inches(0.32), Inches(0.095),
|
||
fill=ACCENT)
|
||
|
||
|
||
g = Inches(0.10) # Abstand Adapter-Linie <-> LIS
|
||
th = Inches(0.08) # Dicke der roten Adapter-Linie
|
||
|
||
# Governance -> obere Adapter-Linie am Kern
|
||
vline(core_cx, gov_y + Inches(0.07), (core_y - g - th) - (gov_y + Inches(0.07)),
|
||
color=LINEC, weight=Pt(1))
|
||
|
||
uw, uh = Inches(1.55), Inches(0.6)
|
||
|
||
|
||
def ums_box(bx, yc, name, icon_fn):
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, bx, yc - uh / 2, uw, uh, fill=UMS, line=LINEC)
|
||
icon_fn(bx + Inches(0.32), yc)
|
||
txt(bx + Inches(0.58), yc - Inches(0.16), uw - Inches(0.64), Inches(0.32), name,
|
||
size=12, color=INK, align=PP_ALIGN.LEFT)
|
||
|
||
|
||
# Umsysteme links -> Adapter-Schichten am linken Kernrand
|
||
lx = Inches(0.8)
|
||
ums_box(lx, Inches(4.6), "Anlieferung", icon_truck)
|
||
ums_box(lx, Inches(5.2), "DFÜ", icon_dfu)
|
||
for yc in (Inches(4.6), Inches(5.2)):
|
||
hline(lx + uw, yc, (core_x - g - th) - (lx + uw))
|
||
|
||
# Umsystem rechts -> Adapter-Linie am rechten Kernrand
|
||
gx = Inches(6.65)
|
||
ums_box(gx, Inches(4.9), "Geräte", icon_device)
|
||
hline(core_x + core_w + g + th, Inches(4.9), gx - (core_x + core_w + g + th))
|
||
|
||
# ---- LIS-Kern -------------------------------------------------------------
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, core_x, core_y, core_w, core_h, fill=NAVY)
|
||
sh = shp(MSO_SHAPE.ROUNDED_RECTANGLE, core_x, core_y, core_w, core_h, fill=NAVY)
|
||
boxtext(sh, "LIS", size=22, color=WHITE, bold=True)
|
||
|
||
|
||
# ---- 5 Adapter-Linien – je Schnittstelle eine, mit Abstand zum Kern -------
|
||
def rbar_v(outer_x, yc, h=Inches(0.55)): # vertikal, linker/rechter Rand
|
||
shp(MSO_SHAPE.RECTANGLE, outer_x, yc - h / 2, th, h, fill=ACCENT)
|
||
|
||
|
||
def rbar_h(xc, outer_y, w): # horizontal, oben/unten
|
||
shp(MSO_SHAPE.RECTANGLE, xc - w / 2, outer_y, w, th, fill=ACCENT)
|
||
|
||
|
||
rbar_v(core_x - g - th, Inches(4.6)) # 1) Anlieferung
|
||
rbar_v(core_x - g - th, Inches(5.2)) # 2) DFÜ
|
||
rbar_h(core_cx, core_y - g - th, Inches(1.15)) # 3) nach oben (Steuerung)
|
||
rbar_v(core_x + core_w + g, Inches(4.9)) # 4) Geräte
|
||
rbar_h(core_cx, core_by + g, core_w - Inches(0.2)) # 5) Fachliche Verarbeitung
|
||
|
||
# Fachliche Verarbeitung (unten): Module an der unteren Adapter-Linie
|
||
mw, mh = Inches(1.7), Inches(0.6)
|
||
my = Inches(6.05)
|
||
for nm, fill, tc, mcx in [("Hochdurchsatz", TINT_T, TEAL, Inches(3.85)),
|
||
("Spezial", TINT_A, AMBER, Inches(5.85))]:
|
||
vline(mcx, core_by + g + th, my - (core_by + g + th), color=LINEC, weight=Pt(1))
|
||
sh = shp(MSO_SHAPE.ROUNDED_RECTANGLE, mcx - mw / 2, my, mw, mh, fill=fill, line=tc, lw=Pt(1.5))
|
||
boxtext(sh, nm, size=12.5, color=INK, bold=True)
|
||
|
||
txt(Inches(2.9), my + mh + Inches(0.12), Inches(4.0), Inches(0.3), "Fachliche Verarbeitung",
|
||
size=12, color=LIGHT, bold=True, align=PP_ALIGN.CENTER)
|
||
|
||
|
||
# ===========================================================================
|
||
# WEITERE LIS – überlappend, nur angedeutet
|
||
# ===========================================================================
|
||
hw_, hh_ = Inches(1.8), Inches(2.0)
|
||
|
||
def mini_lis(hx, hy, faded=False):
|
||
fill = RGBColor(0xF4, 0xF6, 0xF8) if faded else HINT
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, hx, hy, hw_, hh_, fill=fill, line=HINTL, lw=Pt(1.25))
|
||
hdc = shp(MSO_SHAPE.ROUNDED_RECTANGLE, hx, hy, hw_, Inches(0.46),
|
||
fill=HINTL if not faded else RGBColor(0xDF, 0xE4, 0xEA))
|
||
boxtext(hdc, "LIS", size=14, color=NAVY, bold=True)
|
||
for k in range(3):
|
||
yy = hy + Inches(0.66) + k * Inches(0.4)
|
||
shp(MSO_SHAPE.ROUNDED_RECTANGLE, hx + Inches(0.2), yy, hw_ - Inches(0.4),
|
||
Inches(0.28), fill=WHITE, line=HINTL, lw=Pt(0.75))
|
||
|
||
mini_lis(Inches(10.5), Inches(4.35), faded=True)
|
||
mini_lis(Inches(10.0), Inches(4.75), faded=False)
|
||
vline(Inches(10.0) + hw_ / 2, gov_y + Inches(0.07), Inches(4.75) - (gov_y + Inches(0.07)),
|
||
color=LINEC, weight=Pt(1))
|
||
txt(Inches(9.9), Inches(4.35) + hh_ + Inches(0.2), Inches(2.4), Inches(0.35), "weitere LIS",
|
||
size=13, color=LIGHT, align=PP_ALIGN.CENTER)
|
||
|
||
# ---- Mini-Legende ----------------------------------------------------------
|
||
ly = Inches(7.05)
|
||
shp(MSO_SHAPE.RECTANGLE, Inches(7.55), ly - Inches(0.11), th, Inches(0.22), fill=ACCENT)
|
||
txt(Inches(7.8), ly - Inches(0.16), Inches(3.2), Inches(0.32),
|
||
"Adapter-Schicht – je Schnittstelle eine", size=11.5, color=LIGHT)
|
||
|
||
out = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Folie3.pptx")
|
||
prs.save(out)
|
||
print("saved", out)
|