paintworks_v1_0.py

Created by yannis300307

Created on November 05, 2023

12.8 KB

Paintworks est un logiciel de dessin directement utilisable sur Calculatrice Numworks.

Il a été testé sur N0110 mais devrait marcher sur les modèles plus récents.

Ce programme de 500 lignes a quasiment été tapé entièrement sur Calculatrice… Il comprend un choix de 50 couleurs différentes, un outil pinceau et un outil remplissage. Il possède un système de chargement automatique des dessins et un système d’enregistrement manuel des dessins (Car on ne peut pas écrire (et techniquement lire) automatiquement dans le stockage ).

Vous pouvez me faire des retours sur le site de Planet Casio


import kandinsky
import numpy as np
import ion
import time
from math import ceil,sqrt

spx=kandinsky.set_pixel
ds=kandinsky.draw_string
fr=kandinsky.fill_rect

iokd=ion.keydown
IOKU=ion.KEY_UP
IOKD=ion.KEY_DOWN
IOKR=ion.KEY_RIGHT
IOKL=ion.KEY_LEFT
IOKK=ion.KEY_OK

S_W=320
S_H=222

BG_C=(230,230,230)
BGM_C=(200,200,200)
BC=(0,0,0)

MAX_DATA_LEN=213
pa="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-*/():;%=<>?![]{}_"
pa=[i for i in pa]

def cl():fr(0,0,S_W,S_H,BG_C)

class Ehandler:
  def __init__(s):s.kp=[]
  def k_pressed(s,k):
    ap=k in s.kp
    if iokd(k):
      if not ap:s.kp.append(k);return True
    elif ap:s.kp.remove(k)
    return False

class Engine:
  def __init__(s):
    s.sheet=None
    s.curs_x=0
    s.curs_y=0
    s.zoom=10
    s.move_s=0
    s.move_cd=0
    s.co_menu_o=False
    s.tb_menu_o=False
    s.ev_handler=Ehandler()
    s.c_select=0
    s.tb_select=0
    s.open=False
  def controls_curs(s):
    t=0
    lcx=s.curs_x
    lcy=s.curs_y
    if s.move_cd-time.monotonic()<0:
      if iokd(IOKR):
        s.curs_x+=1
        t=1
      if iokd(IOKL):
        s.curs_x-=1
        t=1
      if iokd(IOKU):
        s.curs_y-=1
        t=1
      if iokd(IOKD):
        s.curs_y+=1
        t=1
      if not t:
        s.move_s=0
    if t:
      if s.curs_x<-s.sheet.w//2:
        s.curs_x=-s.sheet.w//2
      if s.curs_x>s.sheet.w//2-1:
        s.curs_x=s.sheet.w//2-1
      if s.curs_y<-s.sheet.h//2:
        s.curs_y=-s.sheet.h//2
      if s.curs_y>s.sheet.h//2-1:
        s.curs_y=s.sheet.h//2-1
      if s.move_s==0:
        s.move_s=1
        s.move_cd=time.monotonic()+0.6
      elif s.move_s==1:
        s.move_cd=time.monotonic()+0.05
    if iokd(IOKK):
      if s.tb_select==0:
        s.sheet.set_at(s.curs_x+s.sheet.w//2,s.curs_y+s.sheet.h//2,s.c_select)
        t=1
      if s.tb_select==1 and not IOKK in s.ev_handler.kp:
          s.sheet.fill(s.curs_x+s.sheet.w//2,s.curs_y+s.sheet.h//2,s.c_select)
          t=2
      if not IOKK in s.ev_handler.kp:
        s.ev_handler.kp.append(IOKK)

    elif IOKK in s.ev_handler.kp:
      s.ev_handler.kp.remove(IOKK)
    
    if iokd(ion.KEY_BACKSPACE):
      s.open=False
    return t,lcx,lcy
  def check_menu(s):
    t=False
    if s.ev_handler.k_pressed(ion.KEY_TOOLBOX):
        s.tb_menu_o=not s.tb_menu_o
        s.co_menu_o=False
        t=True
    if s.ev_handler.k_pressed(ion.KEY_VAR):
        s.co_menu_o=not s.co_menu_o
        s.tb_menu_o=False
        t=True
    return t
  def new(s,w,h):
    s.sheet=Sheet(w,h)
  def render_curs(s):
    x=s.curs_x*s.zoom+S_W//2+s.zoom//2
    y=s.curs_y*s.zoom+S_H//2+s.zoom//2
    c=(0,0,0)
    spx(x-1,y,c);spx(x+1,y,c);spx(x-1,y-1,c);spx(x-1,y+1,c);spx(x+1,y-1,c);spx(x+1,y+1,c);spx(x,y+1,c);spx(x,y-1,c)
    spx(x,y+2,c);spx(x,y-2,c);spx(x,y+3,c);spx(x,y-3,c);spx(x-2,y,c);spx(x+2,y,c);spx(x-3,y,c);spx(x+3,y,c)
  def menus_controls(s):
    t=False
    if s.co_menu_o or s.tb_menu_o:
      if s.ev_handler.k_pressed(IOKR):
        if s.co_menu_o:
          if s.c_select<len(s.sheet.colorp)-1:
            s.c_select+=1
            t=True
        elif s.tb_menu_o:
          s.tb_select+=1
          if s.tb_select>4:
            s.tb_select=4
          t=True

      if s.ev_handler.k_pressed(IOKL):
        if s.co_menu_o:
          if s.c_select>0:
            s.c_select-=1
            t=True
        elif s.tb_menu_o:
          s.tb_select-=1
          if s.tb_select<0:
            s.tb_select=0
          t=True

      if s.ev_handler.k_pressed(IOKD):
        if s.co_menu_o:
          s.c_select+=5
          t=True
          if s.c_select+1>=len(s.sheet.colorp):
            s.c_select=len(s.sheet.colorp)-1

      if s.ev_handler.k_pressed(IOKU):
        if s.co_menu_o:
          s.c_select-=5
          t=True
          if s.c_select<0:
            s.c_select=0

    return t
  def render_menus(s):
    if s.co_menu_o:
      fr(15,S_H-50,S_W-30,50,BGM_C)
      
      fr(15,S_H-50,S_W-30,1,(100,100,100))
      fr(15,S_H-50,1,50,(100,100,100))
      fr(S_W-15,S_H-50,1,50,(100,100,100))

      c_per_row=5
      yi=s.c_select//c_per_row

      for i in range(c_per_row):
        gi=yi*c_per_row+i
        if gi<len(s.sheet.colorp):
          if gi==s.c_select:
            fr(37+i*54,S_H-38,32,32,(255,200,0))
          else:
            fr(39+i*54,S_H-36,28,28,(100,100,100))
        if gi==0:# if transparent
          fr(40,S_H-35,26,26,(230,230,230))
          fr(40,S_H-35,13,13,(50,50,50))
          fr(40+13,S_H-35+13,13,13,(50,50,50))
        else:
          if gi<len(s.sheet.colorp):
            c=s.sheet.colorp[gi]
            fr(40+i*54,S_H-35,26,26,c)
    if s.tb_menu_o:
      fr(15,S_H-50,S_W-30,50,BGM_C)
      c=(100,100,100)
      fr(15,S_H-50,S_W-30,1,c)
      fr(15,S_H-50,1,50,c)
      fr(S_W-15,S_H-50,1,50,c)
      for i in range(5):
        if i==s.tb_select:
          fr(37+i*54,S_H-38,32,32,(255,200,0))
        else:
          fr(39+i*54,S_H-36,28,28,(100,100,100))
        fr(40+i*54,S_H-35,26,26,(200,200,200))
        x=41+i*54
        y=S_H-35
        s.place_ico(i,x,y)
  def place_ico(s,i,x,y):
    cc=s.sheet.colorp[s.c_select]
    if i==0:
      fr(x+5,y+9,1,1,BC);fr(x+6,y+8,1,3,BC);fr(x+7,y+7,1,5,BC);fr(x+8,y+8,1,5,BC);fr(x+9,y+9,1,5,BC);fr(x+10,y+10,1,5,BC);fr(x+11,y+11,1,5,BC);fr(x+12,y+12,1,5,BC);fr(x+13,y+13,1,3,BC);fr(x+14,y+14,1,1,BC)
      fr(x+14,y+18,1,1,cc);fr(x+15,y+17,1,2,cc);fr(x+16,y+16,1,3,cc)
    elif i==1:
      fr(x+5,y+6,12,15,BC);fr(x+7,y+6,8,13,(150,150,150));fr(x+7,y+8,8,11,cc)
      fr(x+3,y+8,2,6,BC);fr(x+20,y+7,3,3,cc)
  def render_UI(s):
    ds("md:",5,22,(0,0,0),BG_C)
    s.place_ico(s.tb_select,33,20)
  def render(s,full=True,lcx=0,lcy=0):
    if full:
      cl()
      if s.sheet != None: s.sheet.render(s.zoom,0,0)
      s.render_menus()
      s.render_UI()
    else:
      if s.sheet != None: s.sheet.render_area(lcx-s.sheet.w//2,lcy-s.sheet.h//2,1,1,0,0,s.zoom)
    s.render_curs()
  def update(s):
    tt=s.check_menu()
    tm=s.menus_controls()
    t=False
    if not (s.co_menu_o or s.tb_menu_o):
      t,lcx,lcy=s.controls_curs()
    if t==1:
      s.render(False,lcx,lcy)
    if tt or t==2: s.render()
    if tm: s.render_menus()
  def loop(s):
    s.curs_x=s.curs_y=0
    s.ev_handler.kp.append(IOKK)
    s.render()
    s.open=True
    while s.open:
      s.update()

class Sheet:
  def __init__(s,w,h):
    s.pixels=np.zeros((w,h),dtype=np.int8)
    s.w,s.h=w,h
    s.colorp=[(0,0,0)]
    s.c_i=1 #0 =no c
  def load(s,pixels,w,h):
    s.pixels=pixels
    s.w=w;s.h=h
  def colorp_add(s,rgb):
    s.colorp.append(rgb)
    s.c_i+=1
  def set_at(s,x,y,c):
    s.pixels[x,y]=c
  def fill(s,x,y,rc):
    bc=s.pixels[x,y]
    if rc==bc: return
    todo=[(x,y)]
    while len(todo)>0:
      for p in todo.copy():
        x,y=p
        if x+1<s.w and s.pixels[x+1,y]==bc and not (x+1,y) in todo:
          todo.append((x+1,y))
        if x-1>=0 and s.pixels[x-1,y]==bc and not (x-1,y) in todo:
          todo.append((x-1,y))
        if y+1<s.h and s.pixels[x,y+1]==bc and not (x,y+1) in todo:
          todo.append((x,y+1))
        if y-1>=0 and s.pixels[x,y-1]==bc and not (x,y-1) in todo:
          todo.append((x,y-1))

        if s.pixels[x,y]==bc:
          s.set_at(x,y,rc)
        todo.remove(p)
  def render(s,z,cx,cy):
    xs=cx-int(s.w*z/2)+S_W//2
    ys=cy-int(s.h*z/2)+S_H//2
    for x in range(s.w):
      for y in range(s.h):
        v=s.pixels[x,y]
        if v: fr(xs+x*z,ys+y*z,z,z,s.colorp[v])
    xe=xs+s.w*z;ye=ys+s.h*z
    for y in range(ys-1,ye+1):
      spx(xs-1,y,(0,0,0));spx(xe,y,(0,0,0))
    for x in range(xs-1,xe+1):
      spx(x,ys-1,(0,0,0));spx(x,ye,(0,0,0))
  def render_area(s,x,y,w,h,cx,cy,z):
    cx+=S_W//2+s.w*z//2
    cy+=S_H//2+s.h*z//2
    for xx in range(x,x+w):
      for yy in range(y,y+h):
        v=s.pixels[xx,yy]
        if v: 
          fr(cx+xx*z,cy+yy*z,z,z,s.colorp[v])
        else:
          fr(cx+xx*z,cy+yy*z,z,z,BG_C)

class SavingMng:
  def __init__(s):
    s.open=False
    s.ev_handler=Ehandler()
    s.select_i=0

  @staticmethod
  def get_save(sh):
    d="";i=0
    for y in range(sh.h):
      for x in range(sh.w):
        p=sh.pixels[x,y]
        d+=pa[p]
    return d
  @staticmethod
  def print_save(sh):
    sav=SavingMng.get_save(sh)
    print("Copy the following string:")
    for i in range(int(ceil(len(sav)/MAX_DATA_LEN))):
      print("'"+sav[i*MAX_DATA_LEN:i*MAX_DATA_LEN+MAX_DATA_LEN]+"'")

  def render_list(s,l):
    fr(15,65,S_W-30,S_H-75,BGM_C)
    c=(230,230,230)
    scr_y=s.select_i//4
    for i in range(min(len(l)-scr_y*4,4)):
      if i+scr_y*4==s.select_i:
        fr(17,67+i*35,S_W-34,36,(200,200,0))
      fr(20,70+i*35,S_W-40,30,c)
      ds(l[i][:26],25,75+i*35,(0,0,0),c)
  def controls(s,l):
    t=0
    if s.ev_handler.k_pressed(IOKU):
      s.select_i-=1
      t=1

    if s.ev_handler.k_pressed(IOKD):
      s.select_i+=1
      t=1
    s.select_i%=len(l)

    if s.ev_handler.k_pressed(IOKK):
      t=2
    return t
  def render(s,l):
    cl()
    ds("Select img:",10,10,BC,BG_C)
    s.render_list(l)
  def loop(s,m,file):
    s.ev_handler.kp.append(IOKK)
    if m and file!=None:
      l=list(file.img.keys())
      l.sort()
      s.render(l)
      t=0
      while t!=2:
        t=s.controls(l)
        if t==1:s.render(l)
      d=file.img[l[s.select_i]]
      return d,int(sqrt(len(d)))
    else:
      cl()
      ds("To load img in paint, create a",5,20,BC,BG_C);ds('"paintload.py" file and put',5,40,BC,BG_C);ds("your images into it like this:",5,60,BC,BG_C)
      ds("img={",5,100,BC,BG_C);ds('  "img name 1":',5,120,BC,BG_C);ds('  "data 1"',5,140,BC,BG_C)
      ds('  +"data 2", # other data',5,160,BC,BG_C);ds('}" # other images',5,180,BC,BG_C)

      time.sleep(6)

  def ask_code(s):
    try:
      file=__import__("paintload")
      if type(file.img)==dict:
        d=s.loop(1,file);sz=d[1];dt=np.zeros((sz,sz),dtype=np.int8)
        for i in range(sz*sz):
          dt[i%sz,i//sz]=pa.index(d[0][i])
        return dt,sz
    except (ImportError,AttributeError):
      s.loop(0,None)

class Main:
  def __init__(s):
    s.en=Engine()
    s.en.new(16,16)
    s.m=MainMenu()
    s.sav_mng=SavingMng()

  def load_c(s):
    for i in colors:
      s.en.sheet.colorp_add(i)

  def mainmenu(s):
    t=s.m.loop()
    if t==0:
      s.startpaint()
      return 1
    if t==1:
      n_sh=s.sav_mng.ask_code()
      if n_sh is None:return 1
      s.en.sheet.load(n_sh[0],n_sh[1],n_sh[1])
      if n_sh[1]:
        s.startpaint()
      return 1
    if t==2:
      s.sav_mng.print_save(s.en.sheet)
    return 0
  def startpaint(s):
    s.en.loop()
  def loop(s):
    s.curs_x=s.curs_y=0
    cont=1
    while cont:
      cont=s.mainmenu()

class MainMenu:
  def __init__(s):
    s.select_btn=0
    s.ev_handler=Ehandler()
    s.open=False

  def controls(s):
    t=0
    if s.ev_handler.k_pressed(IOKD):
        s.select_btn+=1
        t=1

    if s.ev_handler.k_pressed(IOKU):
        if s.select_btn==1 or s.select_btn==2:
          s.select_btn=0
          t=1

    if s.ev_handler.k_pressed(IOKR):
        if s.select_btn==1:
          s.select_btn+=1
          t=1

    if s.ev_handler.k_pressed(IOKL):
        if s.select_btn==2:
          s.select_btn-=1
          t=1

    if s.select_btn<0:
      s.select_btn=0
      t=0
    elif s.select_btn>2:
      s.select_btn=2
      t=0

    if iokd(IOKK):
      s.open=False    
    return t

  def loop(s):
    s.open=True
    s.render()
    while s.open:
      s.update()
    return s.select_btn

  def update(s):
    if s.controls():
      s.rend_btns()

  def render(s):
    cl()
    ds("PaintWorks",(S_W-10*10)//2,45,(0,0,0),BG_C)
    s.rend_btns()

  def rend_btns(s):  
    s.r_btn("New/continue drawing",250,0,100,s.select_btn==0)
    s.r_btn("Load art",120,-65,140,s.select_btn==1)
    s.r_btn("Save art",120,65,140,s.select_btn==2)

  def r_btn(s,txt,w,x,y,select):
    if select:
      c=(170,170,170)
    else:
      c=(200,200,200)
    fr((S_W-w)//2+x,y,w,30,c);fr((S_W-w)//2+x,y,w,1,(150,150,150));fr((S_W-w)//2+x,y+30,w+1,1,(150,150,150));fr((S_W-w)//2+x,y,1,30,(150,150,150));fr((S_W+w)//2+x,y,1,30,(150,150,150))
    ds(txt,(S_W-10*len(txt))//2+x,y+6,(0,0,0),c)

colors=[
(0,0,0),(85,85,85),(170,170,170),(255,255,255),
(51,0,0),(102,0,0),(153,0,0),(204,0,0),(255,0,0),
(0,51,0),(0,102,0),(0,153,0),(0,191,0),(0,255,0),
(0,0,51),(0,0,102),(0,0,153),(0,0,191),(0,0,255),
(51,51,0),(102,102,0),(153,153,0),(191,191,0),(255,255,0),
(0,51,51),(0,102,102),(0,153,153),(0,191,191),(0,255,255),
(51,0,51),(102,0,102),(153,0,153),(191,0,191),(255,0,255),
(42,255,255),(85,255,255),(127,255,255),(170,255,255),(212,255,255),
(255,42,255),(255,85,255),(255,127,255),(255,170,255),(255,212,255),
(255,255,42),(255,255,85),(255,255,127),(255,255,170),(255,255,212),
(42,42,255),(85,85,255),(127,127,255),(170,170,255),(212,212,255),
(255,42,42),(255,85,85),(255,127,127),(255,170,170),(255,212,212),
(42,255,42),(85,255,85),(127,255,127),(170,255,170),(212,255,212),
]

main=Main()
main.load_c()
try:
  main.loop()
except KeyboardInterrupt:
  pass
cl()
ds("Press [ok] to exit.",10,10,(0,0,0),BG_C)