Omnimaga

Calculator Community => Other Calc-Related Projects and Ideas => TI-Nspire => Topic started by: Chockosta on August 06, 2011, 12:38:27 pm

Title: [Lua] Image Editor
Post by: Chockosta on August 06, 2011, 12:38:27 pm
Hello everybody !

Spoiler For Old first post:
A while ago, p2 sent me this PM :
Quote from: p2
can you please try to make a drawing-program for the NI NSPIRE CX CAS?

So I tried that.

It already features :
-Opening and saving ti.images
-Zoom in and zoom out
-A nice color selecting window
-Error messages
-Transparency support

And it will feature :
-Creating blanks images Done
-Pixel-per-pixel drawing Done
-Lines, squares and circles drawing Done
-Text
-Opening and saving BMP files (maybe)

The script is almost 500 lines long.
To open an image, it has to be saved in a string in a "Calculator" application.
I had to rewrite TI.images loading and displaying, because in Lua, "\000" can't be saved in a string. Thanks to Inspired Lua for this page (http://wiki.inspired-lua.org/TI.Image) !
It was supposed to be called Paintbrush, but Google told me that a MacOS software is already called "Paintbrush". Do you have any suggestions ?

EDIT 08/07/2011 : Now you can fill and erase pixels.

EDIT 30/10/2011 : To see the last version, go HERE (http://ourl.ca/12418/257268)


The last version is nSpaint 0.7. It features :


-Two editors : nSpaint for images and nAnima for animations
-A lot of tools : scroll, draw, erase, fill, pick, circle, line, rectangle, fill circle, fill rectangle.
-A native-like GUI (in nAnima too)
-Save, open or create images of any dimensions
-Transparency support
-A file manager, which can be used to delete images (in nAnima too)
-A tool to copy the current image code to the clipboard (really useful to Lua developpers!)
-A tool to paste an image if there's one in the clipboard
-Undo and redo! (5 times max)
-A option to erase all the image
-A nice color selecter
-Tools to flip/rotate the image
-A filter which replace a color with another one
-A filter which erases a color
-Two filters to increase and decrease brightness
-A 'help' window for each tool
-A splash screen (in nAnima too)
-You can move the cursor with the mouse
-The image is automatically moved when the cursor goes off the screen
-The cursor is moved when you scroll

DOWNLOAD (http://www.omnimaga.org/index.php?action=dlattach;topic=9821.0;attach=12450)

Screenies:
(http://i45.servimg.com/u/f45/11/25/11/26/screen26.png)

(The attached screenies are old ones)
Title: Re: [Lua] Image Editor
Post by: Adriweb on August 06, 2011, 12:40:15 pm
Woooow

This is awesome.

Congratulations.

Will definitely download and use !!
Title: Re: [Lua] Image Editor
Post by: Chockosta on August 06, 2011, 12:40:59 pm
Well, for now you can't edit pictures, just load and save them :D
Title: Re: [Lua] Image Editor
Post by: Adriweb on August 06, 2011, 12:43:05 pm
Well, jimbauwens' TI.Image javascript library is available on his website, so you can probably get some interesting editing stuff from there :P


BTW, as usual... source code ? :P
Title: Re: [Lua] Image Editor
Post by: Chockosta on August 06, 2011, 12:51:00 pm
(It will change very soon)
There isn't any class because I don't like object-oriented programmation... Sorry :P

Spoiler For Spoiler:
Data.lua :
Code: [Select]
--DATA
--drawing
status="drawing"
color={225,170,0}
imgString=nil
imgTable=nil
imgZoom=1
imgName="Open any file"
--color select
newColor={200,100,255}
selColor=1
--text request
requested=""
rqstr=""
--error
errtype=""


--MENU
function menuNew() on.charIn("N") end
function menuOpen() on.charIn("O") end
function menuSave() on.charIn("S") end
function menuZIn() on.charIn("+") end
function menuZOut() on.charIn("-") end
function menuDraw() on.charIn("d") end
function menuPaint() on.charIn("p") end
function menuErase() on.charIn("e") end
function menuCHex() on.charIn("h") end
function menuCSel() on.charIn("s") end

menu={
{"File",
 {"New (Shift+n)",menuNew},
 {"Open (Shift+o)",menuOpen},
 {"Save (Shift+s)",menuSave}
},
{"Edit",
 {"Zoom in (+)",menuZIn},
 {"Zoom out (-)",menuZOut}
},
{"Tools",
 {"Draw (d)",menuDraw},
 {"Paint (p)",menuPaint},
 {"Erase (e)",menuErase}
},
{"Color",
 {"Hexadecimal (h)",menuCHex},
 {"Select (s)",menuCSel}
}}
toolpalette.register(menu)
Functions.lua
Code: [Select]
--MATHTOOLS
mathTools={}

function mathTools.base10to2(n)
 local str
 str=""
 if n~=0 then
  while n~=1 do
   str=str..tostring(n%2)
   n=math.floor(n/2)
  end
  str=str..tostring(n%2)
  return string.reverse(str)
 else
  return "0"
 end
end

function mathTools.base2to10(n)
 local num = 0
 local ex = string.len(n) - 1
 local l = 0
 l = ex + 1
 for i = 1, l do
  b = string.sub(n, i, i)
  if b == "1" then
   num = num + 2^ex
  end
  ex = ex - 1
 end
 return num
end

function mathTools.int2Hex(int)
 if int<10 then
  return tostring(int)
 else
  if int==10 then return "A"
  elseif int==11 then return "B"
  elseif int==12 then return "C"
  elseif int==13 then return "D"
  elseif int==14 then return "E"
  elseif int==15 then return "F"
  end
 end
end



--MISCELLANEOUS


function width() return platform.window:width() end
function height() return platform.window:height() end
function refresh() platform.window:invalidate() end


function strch(str,ch)
 local test
 test=nil
 for i=1,string.len(str),1 do
  if string.sub(str,i,i)==ch then
   test=1
  end
 end
 return test
end

function saveFile()
 if rqstr=="" then
  status="error"
  errtype="Please type a name"
 elseif strch("0123456789",string.sub(rqstr,1,1)) then
  status="error"
  errtype="Invalid name"
 else
  var.store(rqstr,imgString)
  imgName=rqstr
 end
end

function loadFile()
 local test
 test=var.recall(rqstr)
 if not test then
  status="error"
  errtype="File does not exist"
 elseif type(test)~="string" then
  status="error"
  errtype="Invalid file"
 else
  imgZoom=1
  imgString=test
  imgTools.img2table(imgString)
  imgName=rqstr
 end
end

function loadHexColor()
 local isHex,tmptable
 isHex=1
 tmptable={}
 if string.len(rqstr)==6 then
  for i=1,6,1 do
   currentch=string.sub(rqstr,i,i)
   if strch("0123456789",currentch) then
    tmptable[i]=tonumber(currentch)
   elseif strch("Aa",currentch) then tmptable[i]=10
   elseif strch("Bb",currentch) then tmptable[i]=11
   elseif strch("Cc",currentch) then tmptable[i]=12
   elseif strch("Dd",currentch) then tmptable[i]=13
   elseif strch("Ee",currentch) then tmptable[i]=14
   elseif strch("Ff",currentch) then tmptable[i]=15
   else isHex=nil end
  end
 else isHex=nil
 end
 if isHex then
  color={tmptable[1]*16+tmptable[2],tmptable[3]*16+tmptable[4],tmptable[5]*16+tmptable[6]}
 else
  status="error"
  errtype="Invalid hexadecimal"
 end
end


imgTools.lua
Code: [Select]
imgTools={}

function imgTools.getPixel(byte1,byte2)
 local str2
 str2=imgTools.eightChars(mathTools.base10to2(tonumber(byte2)))..imgTools.eightChars(mathTools.base10to2(tonumber(byte1)))
 return {tonumber(string.sub(str2,1,1)),mathTools.base2to10(string.sub(str2,2,6)),mathTools.base2to10(string.sub(str2,7,11)),mathTools.base2to10(string.sub(str2,12,16))}
end

function imgTools.getSize(img)
 imgWidth=mathTools.base2to10(mathTools.base10to2(tonumber(string.sub(img,10,12)..string.sub(img,7,9)..string.sub(img,4,6)..string.sub(img,1,3))))
 imgHeight=mathTools.base2to10(mathTools.base10to2(tonumber(string.sub(img,22,24)..string.sub(img,19,21)..string.sub(img,16,18)..string.sub(img,13,15))))
end

function imgTools.threeNumbers(nb)
 if string.len(tostring(nb))==1 then
  return "00"..tostring(nb)
 elseif string.len(tostring(nb))==2 then
  return "0"..tostring(nb)
 else
  return tostring(nb)
 end
end

function imgTools.eightChars(str)
 return string.rep("0",8-string.len(str))..str
end

function imgTools.convertChars(img)
 local finished,img2,index
 index=1
 img2=""
 finished=nil
 while not finished do
  if string.sub(img,index,index)~=[[\]] then
   img2=img2..imgTools.threeNumbers(string.byte(string.sub(img,index,index)))
   index=index+1
  else
   img2=img2..string.sub(img,index+1,index+3)
   index=index+4
  end
  if index>string.len(img) then
   finished=1
  end
 end
 return img2
end

function imgTools.img2table(str)
 local index
 str2=imgTools.convertChars(str)
 imgTable={}
 imgTools.getSize(str2)
 for raw=1,imgHeight do
  imgTable[raw]={}
  for column=1,imgWidth do
   index=(column-1)*6+61+(raw-1)*6*imgWidth
   imgTable[raw][column]=imgTools.getPixel(string.sub(str2,index,index+2),string.sub(str2,index+3,index+5))
  end
 end
end

function imgTools.drawTable(gc,x,y)
 for raw=1,imgHeight do
  for column=1,imgWidth do
   if imgTable[raw][column][1]==1 then
    gc:setColorRGB(imgTable[raw][column][2]*8,imgTable[raw][column][3]*8,imgTable[raw][column][4]*8)
    gc:fillRect((column-1)*imgZoom+x,(raw-1)*imgZoom+y,imgZoom,imgZoom)
    gc:setColorRGB(0,0,0)
    gc:setPen("thin","smooth")
    gc:drawRect(x-1,y-1,imgWidth*imgZoom+1,imgHeight*imgZoom+1)
   end
  end
 end
end


Events.lua
Code: [Select]
--EVENTS
function on.backspaceKey()
 if status=="requesting" then
  rqstr=string.sub(rqstr,1,string.len(rqstr)-1)
  platform.window:invalidate()
 end
end

function on.charIn(ch)
 if status=="drawing" then
  if ch=="+" and imgZoom<8 then
   imgZoom=imgZoom*2
  elseif ch=="-" and imgZoom>1 then
   imgZoom=imgZoom/2
  elseif ch=="O" then
   status="requesting"
   rqstr=""
   requested="File name"
  elseif ch=="S" then
   if not imgString then
    status="error"
    errtype="No opened file"
   else
    status="requesting"
    rqstr=imgName
    requested="Save as"
   end
  elseif ch=="s" then
   status="selectingColor"
   selColor=1
   newColor={math.floor(color[1]/5)*5,math.floor(color[2]/5)*5,math.floor(color[3]/5)*5}
  elseif ch=="h" then
   status="requesting"
   rqstr=""
   requested="Hex code"
  end
 elseif status=="requesting" and string.len(rqstr)<10 and strch("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",ch) then
  rqstr=rqstr..ch
 end
 refresh()
end

function on.escapeKey()
 status="drawing"
 refresh()
end

function on.enterKey()
 if status=="selectingColor" then
  color=newColor
  status="drawing"
 elseif status=="requesting" then
  status="drawing"
  if requested=="Hex code" then
   loadHexColor()
  elseif requested=="File name" then
   rqstr=string.lower(rqstr)
   loadFile()
  elseif requested=="Save as" then
   rqstr=string.lower(rqstr)
   saveFile()
  end
 elseif status=="error" then
  status="drawing"
 end
 refresh()
end

function on.arrowKey(ar)
 if status=="selectingColor" then
  if ar=="up" then
   selColor=selColor-1
  elseif ar=="down" then
   selColor=selColor+1
  elseif ar=="right" and newColor[selColor]<251 then
   newColor[selColor]=newColor[selColor]+5
  elseif ar=="left" and newColor[selColor]>4 then
   newColor[selColor]=newColor[selColor]-5
  end
  if selColor>3 then
   selColor=1
  elseif selColor<1 then
   selColor=3
  end
 end
 refresh()
end
Drawing.lua
Code: [Select]

--DRAWING
function drawColorSelect(gc)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-50,150,100)
 gc:setColorRGB(0,0,0)
 gc:fillRect(width()/2-75,height()/2-50,150,15)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-50,150,100)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString("Select your color",width()/2-73,height()/2-53,"top")
 gc:setColorRGB(0,0,0)
 gc:drawString("Red :",width()/2-73,height()/2-35,"top")
 gc:drawString("Green :",width()/2-73,height()/2-20,"top")
 gc:drawString("Blue :",width()/2-73,height()/2-5,"top")
 for i=0,63 do
  gc:setColorRGB(i*4,newColor[2],newColor[3])
  gc:fillRect(width()/2-23+i,height()/2-30,1,10)
  gc:setColorRGB(newColor[1],i*4,newColor[3])
  gc:fillRect(width()/2-23+i,height()/2-15,1,10)
  gc:setColorRGB(newColor[1],newColor[2],i*4)
  gc:fillRect(width()/2-23+i,height()/2,1,10)
 end
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-23,height()/2-46+selColor*15,64,11)
 for i=1,3 do
  gc:drawString(tostring(newColor[i]),width()/2+52,height()/2-50+i*15,"top")
  gc:fillRect(width()/2-24+newColor[i]/4,height()/2-47+i*15,3,14)
 end
 gc:setColorRGB(color[1],color[2],color[3])
 gc:fillRect(width()/2-70,height()/2+20,30,20)
 gc:setColorRGB(newColor[1],newColor[2],newColor[3])
 gc:fillRect(width()/2-28,height()/2+20,30,20)
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-70,height()/2+20,30,20)
 gc:drawRect(width()/2-28,height()/2+20,30,20)
 gc:drawString(mathTools.int2Hex(math.floor(newColor[1]/16))..mathTools.int2Hex(newColor[1]%16)..mathTools.int2Hex(math.floor(newColor[2]/16))..mathTools.int2Hex(newColor[2]%16)..mathTools.int2Hex(math.floor(newColor[3]/16))..mathTools.int2Hex(newColor[3]%16),width()/2+20,height()/2+20,"top")
 gc:drawString("Old     New",width()/2-65,height()/2+21,"top")
end

function drawRequest(gc,msg)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-25,150,50)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-25,150,50)
 gc:fillRect(width()/2-75,height()/2-25,150,15)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString(msg,width()/2-70,height()/2-28,"top")
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-70,height()/2,140,20)
 gc:drawString(rqstr,width()/2-65,height()/2,"top")
end

function drawError(gc)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-20,150,40)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-20,150,40)
 gc:fillRect(width()/2-75,height()/2-20,150,15)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString("Error",width()/2-73,height()/2-23,"top")
 gc:setColorRGB(0,0,0)
 gc:drawString(errtype,width()/2-70,height()/2-5,"top")
end

function on.paint(gc)
 gc:setColorRGB(color[1],color[2],color[3])
 gc:fillRect(0,0,20,15)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(0,0,20,15)
 gc:setFont("sansserif","r",10)
 gc:drawString(imgName.." ("..tostring(imgZoom*100).."%)",25,0,"top")
 if imgTable then
  imgTools.drawTable(gc,30,30)
 end
 if status=="selectingColor" then
  drawColorSelect(gc)
 elseif status=="requesting" then
  drawRequest(gc,requested)
 elseif status=="error" then
  drawError(gc)
 end
 gc:setColorRGB(0,0,0)
 gc:setFont("sansserif","r",8)
 gc:drawString("Lua Paintbrush - Par Loic Pujet",10,height()-12,"top")
end
Title: Re: [Lua] Image Editor
Post by: ExtendeD on August 06, 2011, 01:21:46 pm
Nice tool Chockosta :)
Title: Re: [Lua] Image Editor
Post by: Hayleia on August 06, 2011, 01:55:26 pm
This is a great tool ! Why don't I have an nspire ?! :'(
It was supposed to be called Paintbrush, but Google told me that a MacOS software is already called "Paintbrush". Do you have any suggestions ?
Maybe a mix between MS Paint and Nspire that gives nSpaint ?
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on August 06, 2011, 02:32:17 pm
Looks very nice!
Good to use with on calc editors :)

Quote
Thanks to Inspired Lua for this page !
I'm glad you liked it :)
I have actually wrote a better, simpler version, but haven't taken the time to upload it.
Title: Re: [Lua] Image Editor
Post by: DJ Omnimaga on August 06, 2011, 03:52:30 pm
That's very great! Nice job so far!
Title: Re: [Lua] Image Editor
Post by: Chockosta on August 07, 2011, 11:01:22 am
Draw and erase tools !
Tomorrow, it will be possible to create new images...
Title: Re: [Lua] Image Editor
Post by: pianoman on August 08, 2011, 03:05:20 pm
This is absolutely amazing :)
Nice work, as usual!
Title: Re: [Lua] Image Editor
Post by: Deep Toaster on August 08, 2011, 03:07:35 pm
Waoh, awesome! We're seriously short of on-calc Nspire tools right now.
Title: Re: [Lua] Image Editor
Post by: critor on August 08, 2011, 03:27:59 pm
Draw and erase tools !

Did you update the 1st post tns attachment?
Unless I have a cache problem, it is byte to byte identic with the one I downloaded 2 days ago...
Title: Re: [Lua] Image Editor
Post by: p2 on August 09, 2011, 06:30:47 am
Thanx, Chockosta!!!
Looks really great!!
It's exactly what I thought of!!

+1    (+4 wasn't possible...)



Spoiler For Chockosta:
Next project for you:
A program to show .GIF-images and a special software to send them to the TI.
Title: Re: [Lua] Image Editor
Post by: BrownyTCat on August 09, 2011, 11:43:25 am
I just have a small suggestion that could possibly be added later. There's a boolean that returns true if the calc is color, but if it's greyscale it returns false, you could make only one slider for the grey level in the color selector.
Title: Re: [Lua] Image Editor
Post by: Chockosta on August 09, 2011, 01:57:52 pm
New features !
-Creating new images
-Nice sprites for tools
-When a file is modified but not saved, there's a '*' before its name
-The program now shows the image size

Now it can be used as a sprite creator for on-calc Lua, but it still lacks scrolling (if you want very large sprites).

Maybe a mix between MS Paint and Nspire that gives nSpaint ?
I like your idea ! It's now called nSpaint

Did you update the 1st post tns attachment?
Unless I have a cache problem, it is byte to byte identic with the one I downloaded 2 days ago...
Oh, I forgot that ! Sorry. The latest version is attached to this post.

I just have a small suggestion that could possibly be added later. There's a boolean that returns true if the calc is color, but if it's greyscale it returns false, you could make only one slider for the grey level in the color selector.
Even if we can't see the color, I think that it's useful to create RGB pictures on greyscale calcs (because we can send pictures/lua scripts to CX calcs)
Title: Re: [Lua] Image Editor
Post by: pianoman on August 09, 2011, 02:23:00 pm
Once again, nice job!
Updated code please?
Title: Re: [Lua] Image Editor
Post by: Levak on August 09, 2011, 02:32:47 pm
Updated code please?

Answer :

Oh, I forgot that ! Sorry. The latest version is attached to this post.

=)
Title: Re: [Lua] Image Editor
Post by: pianoman on August 09, 2011, 02:33:49 pm
Once again, nice job!
Updated code please?

Answer :

Oh, I forgot that ! Sorry. The latest version is attached to this post.

=)
I meant the Lua source code :D
Title: Re: [Lua] Image Editor
Post by: Chockosta on August 09, 2011, 02:35:41 pm
Here it is (now 600 lines !) :

Spoiler For Spoiler:
Data.lua :
Code: [Select]

--DATA
--drawing
status="drawing"
tool=nil
xpos=1
ypos=1
color={225,170,0}
changedMark=""
--image
imgString=nil
imgTable=nil
imgZoom=1
imgName=""
--color select
newColor={200,100,255}
selColor=1
--text request
requested=""
rqstr=""
--error
errtype=""
--tools sprites - 1:move  2:draw  3:erase
toolsSprites={}
toolsSprites[1]=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202_\202_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128_\202\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\000\128\255\255\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\255\255\255\255\000\128\000\128\000\128_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202\000\128\255\255\000\128\000\128\255\255\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\255\255\255\255\000\128\000\128\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128_\202\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202_\202_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites[2]=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\011\202N\218-\214-\210\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\167\193p\230Z\255\148\254h\225e\185\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\234\197\145\222Y\255\148\254\140\253\164\240\001\173\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\167\189L\214\024\227\247\226\173\249\132\252$\209\012\202\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\168\193(\214\206\238h\230\213\218\239\229\226\208\234\197\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\168\193\008\210\238\238g\234#\226*\210\202\209\200\193\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\200\193\231\205\238\242h\234$\226\162\201B\185\168\193\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\200\193\231\205\238\242\136\234#\226\162\201\034\185\201\197\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\168\193\231\205\238\242\136\234#\226\162\201!\181\234\197\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\167\193\007\210\238\242\136\234#\226\162\201!\181\011\202\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\167\189(\214\238\238\136\234$\226\162\201!\181\011\202\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\012\202)\210\204\238g\234$\226\162\201!\181\235\201\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\134\189\240\230u\243\170\234\130\197B\185\202\197\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\232\201\016\235S\243\016\239A\185\168\193\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\012\202\144\214\208\230\008\210#\181\234\197\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\168\193\167\193e\185O\210\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\000\128\255\255\255\255\000\128\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites[3]=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255y\182\215\157\215\157\214\157\214\157\214\157\214\157\214\157\181\157\180\153z\190\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255y\186\215\157\028\215\219\206\219\202\219\202\219\202\219\202\219\202\219\202\219\202/\149Y\182\255\255\000\128\000\128\255\255\255\255\255\255\219\202\215\157<\219\187\198\187\198\187\198\187\198\187\198\187\198\187\198\186\198\028\215\154\190Q\149\255\255\000\128\000\128\255\255\255\255\255\255P\149<\219\219\202\187\198\187\198\187\198\187\198\187\198\187\198\187\198\187\198\028\215\024\170Q\149\255\255\000\128\000\128\255\255\255\255P\149<\219<\219\180\238\180\238\180\242\180\242\180\242\180\242\180\242\147\242\028\215\187\198\024\170Q\149\255\255\000\128\000\128\255\255\255\255\173\245\023\247\180\242\180\242\180\242\180\242\180\242\180\242\180\242\147\242\180\242\023\243r\242\024\170Q\149\255\255\000\128\000\128\255\255\238\245r\246\214\242\180\238\180\242\180\242\180\242\180\242\180\242\180\242\147\242\213\242\147\246r\242Q\149\255\255\255\255\000\128\000\128\255\255Q\246\024\247\180\242\180\242\180\242\148\242\148\242\148\242\147\242\147\242\180\242\246\242r\242\015\242Q\149\255\255\255\255\000\128\000\128\255\255\239\245\246\242\180\242\180\242\180\242\180\242\148\242\147\242\148\246\147\246\181\246\214\246r\246\198\248\255\255\255\255\255\255\000\128\000\128\255\255\238\2459\2478\2518\2518\2518\2518\2518\2518\2518\251\023\251R\250\173\245)\237\255\255\255\255\255\255\000\128\000\128\255\255\140\245\016\254\207\253\239\253\239\253\239\253\239\253\239\253\239\253\239\253\206\253\206\249\231\244\255\255\255\255\255\255\255\255\000\128\000\128\255\255k\245R\2501\2501\2501\2501\2501\2501\2501\2501\2501\250\140\249(\233\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\198\248\166\248\198\248\198\248\198\248\198\248\198\248\198\248\198\248\198\248\198\244\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")

--MENU
function menuNew() on.charIn("N") end
function menuOpen() on.charIn("O") end
function menuSave() on.charIn("S") end
function menuZIn() on.charIn("+") end
function menuZOut() on.charIn("-") end
function menuDraw() on.charIn("d") end
function menuPaint() on.charIn("p") end
function menuErase() on.charIn("e") end
function menuCHex() on.charIn("h") end
function menuCSel() on.charIn("s") end

menu={
{"File",
 {"New (Shift+n)",menuNew},
 {"Open (Shift+o)",menuOpen},
 {"Save (Shift+s)",menuSave}
},
{"Edit",
 {"Zoom in (+)",menuZIn},
 {"Zoom out (-)",menuZOut}
},
{"Tools",
 {"Draw (d)",menuDraw},
 {"Paint (p)",menuPaint},
 {"Erase (e)",menuErase}
},
{"Color",
 {"Hexadecimal (h)",menuCHex},
 {"Select (s)",menuCSel}
}}
toolpalette.register(menu)

Functions.lua
Code: [Select]

--MATHTOOLS
mathTools={}

function mathTools.base10to2(n)
 local str
 str=""
 if n~=0 then
  while n~=1 do
   str=str..tostring(n%2)
   n=math.floor(n/2)
  end
  str=str..tostring(n%2)
  return string.reverse(str)
 else
  return "0"
 end
end

function mathTools.base2to10(n)
 local num = 0
 local ex = string.len(n) - 1
 local l = 0
 l = ex + 1
 for i = 1, l do
  b = string.sub(n, i, i)
  if b == "1" then
   num = num + 2^ex
  end
  ex = ex - 1
 end
 return num
end

function mathTools.int2Hex(int)
 if int<10 then
  return tostring(int)
 else
  if int==10 then return "A"
  elseif int==11 then return "B"
  elseif int==12 then return "C"
  elseif int==13 then return "D"
  elseif int==14 then return "E"
  elseif int==15 then return "F"
  end
 end
end



--MISCELLANEOUS


function width() return platform.window:width() end
function height() return platform.window:height() end
function refresh() platform.window:invalidate() end


function strch(str,ch)
 local test
 test=nil
 for i=1,string.len(str),1 do
  if string.sub(str,i,i)==ch then
   test=1
  end
 end
 return test
end

function saveFile()
 if rqstr=="" then
  status="error"
  errtype="Please type a name"
 elseif strch("0123456789",string.sub(rqstr,1,1)) then
  status="error"
  errtype="Invalid name"
 else
  imgString=imgTools.table2img()
  var.store(rqstr,imgString)
  imgName=rqstr
  changedMark=""
 end
end

function loadFile()
 local test
 test=var.recall(rqstr)
 if not test then
  status="error"
  errtype="File does not exist"
 elseif type(test)~="string" then
  status="error"
  errtype="Invalid file"
 else
  imgZoom=1
  xpos=1
  ypos=1
  tool=nil
  changedMark=""
  imgString=test
  imgTools.img2table(imgString)
  imgName=rqstr
 end
end

function newFile()
 imgWidth=tempVarWidth
 imgHeight=tonumber(rqstr)
 imgZoom=1
 xpos=1
 ypos=1
 tool=nil
 changedMark=""
 imgName="unsaved"
 imgTable={}
 for i=1,imgHeight do
  imgTable[i]={}
  for j=1,imgWidth do
   imgTable[i][j]={0,0,0,0}
  end
 end
end

function loadHexColor()
 local isHex,tmptable
 isHex=1
 tmptable={}
 if string.len(rqstr)==6 then
  for i=1,6,1 do
   currentch=string.sub(rqstr,i,i)
   if strch("0123456789",currentch) then
    tmptable[i]=tonumber(currentch)
   elseif strch("Aa",currentch) then tmptable[i]=10
   elseif strch("Bb",currentch) then tmptable[i]=11
   elseif strch("Cc",currentch) then tmptable[i]=12
   elseif strch("Dd",currentch) then tmptable[i]=13
   elseif strch("Ee",currentch) then tmptable[i]=14
   elseif strch("Ff",currentch) then tmptable[i]=15
   else isHex=nil end
  end
 else isHex=nil
 end
 if isHex then
  color={tmptable[1]*16+tmptable[2],tmptable[3]*16+tmptable[4],tmptable[5]*16+tmptable[6]}
 else
  status="error"
  errtype="Invalid hexadecimal"
 end
end



imgTools.lua
Code: [Select]

imgTools={}

function imgTools.getPixel(byte1,byte2)
 local str2
 str2=imgTools.addZeros(mathTools.base10to2(tonumber(byte2)),8)..imgTools.addZeros(mathTools.base10to2(tonumber(byte1)),8)
 return {tonumber(string.sub(str2,1,1)),mathTools.base2to10(string.sub(str2,2,6)),mathTools.base2to10(string.sub(str2,7,11)),mathTools.base2to10(string.sub(str2,12,16))}
end

function imgTools.getSize(img)
 imgWidth=mathTools.base2to10(mathTools.base10to2(tonumber(string.sub(img,10,12)..string.sub(img,7,9)..string.sub(img,4,6)..string.sub(img,1,3))))
 imgHeight=mathTools.base2to10(mathTools.base10to2(tonumber(string.sub(img,22,24)..string.sub(img,19,21)..string.sub(img,16,18)..string.sub(img,13,15))))
end

function imgTools.addZeros(str,strSize)
 return string.rep("0",strSize-string.len(str))..str
end

function imgTools.convertChars(img)
 local finished,img2,index
 index=1
 img2=""
 finished=nil
 while not finished do
  if string.sub(img,index,index)~=[[\]] then
   img2=img2..imgTools.addZeros(tostring(string.byte(string.sub(img,index,index))),3)
   index=index+1
  else
   img2=img2..string.sub(img,index+1,index+3)
   index=index+4
  end
  if index>string.len(img) then
   finished=1
  end
 end
 return img2
end

function imgTools.generateHeader()
 local binaryHeader,header
 binaryHeader={}
 binaryHeader[1]=imgTools.addZeros(mathTools.base10to2(imgWidth),32)
 binaryHeader[2]=imgTools.addZeros(mathTools.base10to2(imgHeight),32)
 binaryHeader[3]=imgTools.addZeros(mathTools.base10to2(imgWidth*2),32)
 header={"","",""}
 for i=1,3 do
  for j=3,0,-1 do
   header[i]=header[i]..imgTools.addZeros(tostring(mathTools.base2to10(string.sub(binaryHeader[i],8*j+1,8*(j+1)))),3)
  end
 end
 return header[1]..header[2].."000000000000"..header[3].."016000001000"
end

function imgTools.convertPixel(pixel)
 local str
 str=tostring(pixel[1])..imgTools.addZeros(mathTools.base10to2(pixel[2]),5)..imgTools.addZeros(mathTools.base10to2(pixel[3]),5)..imgTools.addZeros(mathTools.base10to2(pixel[4]),5)
 return imgTools.addZeros(tostring(mathTools.base2to10(string.sub(str,9,16))),3)..imgTools.addZeros(tostring(mathTools.base2to10(string.sub(str,1,8))),3)
end

function imgTools.addSlashes(str)
 local finished,str2,index
 finished=nil
 str2=[[\]]..str
 index=1
 while not finished do
  index=index+4
  if index>string.len(str2) then
   finished=1
  else
   str2=string.sub(str2,1,index-1)..[[\]]..string.sub(str2,index)
  end
 end
 return str2
end

function imgTools.img2table(str)
 local index
 str2=imgTools.convertChars(str)
 imgTable={}
 imgTools.getSize(str2)
 for raw=1,imgHeight do
  imgTable[raw]={}
  for column=1,imgWidth do
   index=(column-1)*6+61+(raw-1)*6*imgWidth
   imgTable[raw][column]=imgTools.getPixel(string.sub(str2,index,index+2),string.sub(str2,index+3,index+5))
  end
 end
end

function imgTools.drawTable(gc,x,y)
 gc:setPen("thin","dashed")
 gc:drawRect(x-1,y-1,imgWidth*imgZoom+1,imgHeight*imgZoom+1)
 gc:setPen("thin","smooth")
 for raw=1,imgHeight do
  for column=1,imgWidth do
   if imgTable[raw][column][1]==1 then
    gc:setColorRGB(imgTable[raw][column][2]*8,imgTable[raw][column][3]*8,imgTable[raw][column][4]*8)
    gc:fillRect((column-1)*imgZoom+x,(raw-1)*imgZoom+y,imgZoom,imgZoom)
    gc:setColorRGB(0,0,0)
   end
  end
 end
end

function imgTools.table2img()
 local imgStr
 imgStr=imgTools.generateHeader()
 for i=1,imgHeight do
  for j=1,imgWidth do
   imgStr=imgStr..imgTools.convertPixel(imgTable[i][j])
  end
 end
 return imgTools.addSlashes(imgStr)
end





Events.lua
Code: [Select]

--EVENTS
function on.backspaceKey()
 if status=="requesting" then
  rqstr=string.sub(rqstr,1,string.len(rqstr)-1)
  platform.window:invalidate()
 end
end

function on.charIn(ch)
 if status=="drawing" then
  if ch=="+" and imgZoom<8 then
   imgZoom=imgZoom*2
  elseif ch=="-" and imgZoom>1 then
   imgZoom=imgZoom/2
  elseif ch=="d" then
   tool="draw"
  elseif ch=="e" then
   tool="erase"
  elseif ch=="N" then
   status="requesting"
   rqstr=""
   requested="Image width"
  elseif ch=="O" then
   status="requesting"
   rqstr=""
   requested="File name"
  elseif ch=="S" then
   if not imgTable then
    status="error"
    errtype="No opened file"
   else
    status="requesting"
    rqstr=imgName
    requested="Save as"
   end
  elseif ch=="s" then
   status="selectingColor"
   selColor=1
   newColor={math.floor(color[1]/5)*5,math.floor(color[2]/5)*5,math.floor(color[3]/5)*5}
  elseif ch=="h" then
   status="requesting"
   rqstr=""
   requested="Hex code"
  end
 elseif status=="requesting" and string.len(rqstr)<10 and strch("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",ch) then
  rqstr=rqstr..ch
 end
 refresh()
end

function on.escapeKey()
 if status=="drawing" then
  tool=nil
 else
  status="drawing"
 end
 refresh()
end

function on.enterKey()
 if status=="drawing" then
  if tool=="draw" then
   imgTable[ypos][xpos]={1,math.floor(color[1]/8),math.floor(color[2]/8),math.floor(color[3]/8)}
   changedMark="*"
  elseif tool=="erase" then
   imgTable[ypos][xpos][1]=0
   changedMark="*"
  end
 elseif status=="selectingColor" then
  color=newColor
  status="drawing"
 elseif status=="requesting" then
  status="drawing"
  if requested=="Hex code" then
   loadHexColor()
  elseif requested=="Image width" then
   if tonumber(rqstr) and tonumber(rqstr)~=0 then
    tempVarWidth=tonumber(rqstr)
    status="requesting"
    requested="Image height"
    rqstr=""
   else
    status="error"
    errtype="Invalid number"
   end
  elseif requested=="Image height" then
   if tonumber(rqstr) and tonumber(rqstr)~=0 then
    if tonumber(rqstr)*tempVarWidth>3000 then
     status="error"
     errtype="Overflow (3000 px max)"
    else
     newFile()
    end
   else
    status="error"
    errtype="Invalid number"
   end
  elseif requested=="File name" then
   rqstr=string.lower(rqstr)
   loadFile()
  elseif requested=="Save as" then
   rqstr=string.lower(rqstr)
   saveFile()
  end
 elseif status=="error" then
  status="drawing"
 end
 refresh()
end

function on.arrowKey(ar)
 if status=="drawing" and tool and imgTable then
  if ar=="up" and ypos>1 then ypos=ypos-1 end
  if ar=="down" and ypos<imgHeight then ypos=ypos+1 end
  if ar=="left" and xpos>1 then xpos=xpos-1 end
  if ar=="right" and xpos<imgWidth then xpos=xpos+1 end
 elseif status=="selectingColor" then
  if ar=="up" then
   selColor=selColor-1
  elseif ar=="down" then
   selColor=selColor+1
  elseif ar=="right" and newColor[selColor]<251 then
   newColor[selColor]=newColor[selColor]+5
  elseif ar=="left" and newColor[selColor]>4 then
   newColor[selColor]=newColor[selColor]-5
  end
  if selColor>3 then
   selColor=1
  elseif selColor<1 then
   selColor=3
  end
 end
 refresh()
end

Drawing.lua
Code: [Select]


--DRAWING
function drawColorSelect(gc)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-50,150,100)
 gc:setColorRGB(0,0,0)
 gc:fillRect(width()/2-75,height()/2-50,150,15)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-50,150,100)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString("Select your color",width()/2-73,height()/2-53,"top")
 gc:setColorRGB(0,0,0)
 gc:drawString("Red :",width()/2-73,height()/2-35,"top")
 gc:drawString("Green :",width()/2-73,height()/2-20,"top")
 gc:drawString("Blue :",width()/2-73,height()/2-5,"top")
 for i=0,63 do
  gc:setColorRGB(i*4,newColor[2],newColor[3])
  gc:fillRect(width()/2-23+i,height()/2-30,1,10)
  gc:setColorRGB(newColor[1],i*4,newColor[3])
  gc:fillRect(width()/2-23+i,height()/2-15,1,10)
  gc:setColorRGB(newColor[1],newColor[2],i*4)
  gc:fillRect(width()/2-23+i,height()/2,1,10)
 end
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-23,height()/2-46+selColor*15,64,11)
 for i=1,3 do
  gc:drawString(tostring(newColor[i]),width()/2+52,height()/2-50+i*15,"top")
  gc:fillRect(width()/2-24+newColor[i]/4,height()/2-47+i*15,3,14)
 end
 gc:setColorRGB(color[1],color[2],color[3])
 gc:fillRect(width()/2-70,height()/2+20,30,20)
 gc:setColorRGB(newColor[1],newColor[2],newColor[3])
 gc:fillRect(width()/2-28,height()/2+20,30,20)
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-70,height()/2+20,30,20)
 gc:drawRect(width()/2-28,height()/2+20,30,20)
 gc:drawString(mathTools.int2Hex(math.floor(newColor[1]/16))..mathTools.int2Hex(newColor[1]%16)..mathTools.int2Hex(math.floor(newColor[2]/16))..mathTools.int2Hex(newColor[2]%16)..mathTools.int2Hex(math.floor(newColor[3]/16))..mathTools.int2Hex(newColor[3]%16),width()/2+20,height()/2+20,"top")
 gc:drawString("Old     New",width()/2-65,height()/2+21,"top")
end

function drawRequest(gc,msg)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-25,150,50)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-25,150,50)
 gc:fillRect(width()/2-75,height()/2-25,150,15)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString(msg,width()/2-70,height()/2-28,"top")
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-70,height()/2,140,20)
 gc:drawString(rqstr,width()/2-65,height()/2,"top")
end

function drawError(gc)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-20,150,40)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-20,150,40)
 gc:fillRect(width()/2-75,height()/2-20,150,15)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString("Error",width()/2-73,height()/2-23,"top")
 gc:setColorRGB(0,0,0)
 gc:drawString(errtype,width()/2-70,height()/2-5,"top")
end

function drawCursor(gc)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect((xpos-1)*imgZoom+29,(ypos-1)*imgZoom+29,imgZoom+1,imgZoom+1)
 gc:setColorRGB(255,255,255)
 gc:drawRect((xpos-1)*imgZoom+30,(ypos-1)*imgZoom+30,imgZoom-1,imgZoom-1)
end

function drawTool(gc)
 local id
 if not tool then
  id=1
 elseif tool=="draw" then
  id=2
 elseif tool=="erase" then
  id=3
 end
 if id then
  gc:drawImage(toolsSprites[id],0,15)
 end
end

function on.paint(gc)
 gc:setColorRGB(color[1],color[2],color[3])
 gc:fillRect(0,0,20,15)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(0,0,19,15)
 drawTool(gc)
 gc:setFont("sansserif","r",10)
 if imgTable then
  gc:drawString(changedMark..imgName.." - "..tostring(imgWidth).."x"..tostring(imgHeight).." ("..tostring(imgZoom*100).."%)",25,0,"top")
 else
  gc:drawString("Open or create a file",25,0,"top")
 end
 if imgTable then
  imgTools.drawTable(gc,30,30)
  if tool then
   drawCursor(gc)
  end
 end
 if status=="selectingColor" then
  drawColorSelect(gc)
 elseif status=="requesting" then
  drawRequest(gc,requested)
 elseif status=="error" then
  drawError(gc)
 end
 gc:setColorRGB(0,0,0)
 gc:setFont("sansserif","r",8)
 gc:drawString("Lua nSpaint - Par Loic Pujet",10,height()-12,"top")
end

Title: Re: [Lua] Image Editor
Post by: Levak on August 09, 2011, 02:38:58 pm
I meant the Lua source code :D

Oh, sorry !
Title: Re: [Lua] Image Editor
Post by: pianoman on August 09, 2011, 02:41:14 pm
Not a problem, Levak :D
And thanks, Chockosta!
Title: Re: [Lua] Image Editor
Post by: Chockosta on August 10, 2011, 01:43:02 pm
New version !

New :
-Fill tool
-Color pick tool
-Scrolling when no tool selected

And some bugs fixed...

Title: Re: [Lua] Image Editor
Post by: p2 on August 10, 2011, 01:52:14 pm
what's about transparencity of colours?

or colours which are like small GIF-pictures (blinking like them: )  :hyper: *.*
Title: Re: [Lua] Image Editor
Post by: Chockosta on August 10, 2011, 02:03:10 pm
Transparency is impossible... A pixel can only be 0% transparent or 100%transparent (with ti.images).
By the way, when you use the erase tool, the pixel become transparent, but as the background is white, it looks like the pixel is white.

And for animations, ti.images don't support that...
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on August 10, 2011, 02:04:40 pm
Well, you can show many after each other :)
Although I fear that would be to slow (might work good for small sprites).
Title: Re: [Lua] Image Editor
Post by: fb39ca4 on August 10, 2011, 02:13:27 pm
The editor could make an array of ti.images for an animated sprite, and have a timeline for scrolling between frames.
Title: Re: [Lua] Image Editor
Post by: Chockosta on August 10, 2011, 02:15:20 pm
That's a good idea !

But, I will first add basic tools (line, circle, etc)
Title: Re: [Lua] Image Editor
Post by: BrownyTCat on August 10, 2011, 04:54:35 pm
Would anyone be able to upload a compiled version? I can't compile since I can't find a free and working compiler other than the weird trial of Student Software.

EDIT: I mean a new compiled one, not the old one in the OP.
Title: Re: [Lua] Image Editor
Post by: ExtendeD on August 10, 2011, 05:10:11 pm
Did you try Luna (http://www.ticalc.org/archives/files/fileinfo/441/44113.html)?
Title: Re: [Lua] Image Editor
Post by: BrownyTCat on August 10, 2011, 05:36:18 pm
Did you try Luna (http://www.ticalc.org/archives/files/fileinfo/441/44113.html)?
Just saw it and was amazed.
Title: Re: [Lua] Image Editor
Post by: Chockosta on August 11, 2011, 08:34:50 am
I attached the new version in that post (http://ourl.ca/12418/234532)
Title: Re: [Lua] Image Editor
Post by: Chockosta on September 03, 2011, 09:26:42 am
Up !

nSpaint version 0.4...
-Transperent pixels are now different from white pixels.

As you can see, almost nothing changed...
But I made a new app : nAnima ! It allows you to make animations.
It is supposed to be in the same document as the nSpaint app.
You just have to create images with nSpaint, save them, and open them with nAnima. You can :
-Add, insert and remove frames
-Save and open animations
-Set the framerate (from 0.2 FPS to 100 FPS)
-Play the animation loop.

I made a video (http://www.youtube.com/watch?v=V87Xq4sCzxg&feature=channel_video_title) showing two animations (With the emulator. Unfortunately, it is awfully slow with TI nSpire CAS software, so I can't show color)

I attach screenies and the latest release.
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on September 03, 2011, 11:04:11 am
Very nice work :)
Do you know how fast it is with bigger sprites?
Title: Re: [Lua] Image Editor
Post by: pianoman on September 03, 2011, 11:13:33 am
That is really nice work, Chockosta! Great job!/me runs to do something with it :P
Title: Re: [Lua] Image Editor
Post by: Chockosta on September 03, 2011, 11:33:23 am
@pianoman : Thanks !
@jimbauwens : unfortunately, you can't put more than ~3000 pixels in a document string :(
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on September 04, 2011, 12:38:19 pm
Well, maybe you can store your data in a list (or matrix). That way I guess you can have much more data :)
Title: Re: [Lua] Image Editor
Post by: Chockosta on September 07, 2011, 07:15:34 am
Oh, sorry, I did'nt see your answer.

This could be a good solution, but I want my images to be compatible with image.new() if the user wants to add them in a Lua program.
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on September 07, 2011, 09:37:12 am
Well, just load the list into a table, and use a for loop to generate the images.

Code: [Select]
--basic
{"image1", "image2", "image3" .... "image1337"}-->listpic

--lua
img_d  = var.recall("listpic")
img = {}
for i, #img_d do
  img[i] = image.new(img_d[i])
end


Something like that :)
Title: Re: [Lua] Image Editor
Post by: Chockosta on September 08, 2011, 11:46:11 am
Oh, that's already what I do !
I thought you told me to put image's pixels in a table.

Actually, you can't use image.new(), because you have to convert "\xxx" in one character. (I can't explain really well because of my poor English, but here is a code : )
Spoiler For Spoiler:
Code: [Select]
function newImage(str)
 local str2,finished,index="",nil,1
 while not finished do
  if string.sub(str,index,index)==[[\]] then
   str2=str2..string.char(tonumber(string.sub(str,index+1,index+3)))
   index=index+4
  else
   str2=str2..string.sub(str,index,index)
   index=index+1
  end
  if index>string.len(str) then
   finished=1
  end
 end
 return image.new(str2)
end
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on September 08, 2011, 03:42:23 pm
Hmm, don't really understand, but here is one thing you should know:
Code: [Select]
"\123" == string.char(123)
\ codes are just ways to represent ascii chars :)

I should modify the wiki page, it isn't so clear now.
Title: Re: [Lua] Image Editor
Post by: Chockosta on September 09, 2011, 02:35:35 pm
That's exactly what my code does.
It takes all "\xxx" and add string.char(xxx) to a string, then send the string to image.new()
Title: Re: [Lua] Image Editor
Post by: Chockosta on September 12, 2011, 01:27:42 pm
Up !

Nspaint 0.5 !

-Circle tool
-Rectangle tool
-Line tool
-some optimisations

Code (800 lines :P ) :
Spoiler For Code:
actions.lua
Spoiler For Spoiler:
Code: [Select]
--MISC ACTIONS

function menuAction(action)
 if string.find("NOS",action) then
  fileAction(action)
 elseif string.find("+-",action) then
  setZoom(action)
 elseif string.find("defpclr",action) then
  selectTool(action)
 elseif string.find("hs",action) then
  setColor(action)
 end
 refresh()
end

function fileAction(action)
 if action=="N" then
  status="requesting"
  rqstr=""
  requested="Image width"
 elseif action=="O" then
  status="requesting"
  rqstr=""
  requested="File name"
 elseif action=="S" then
  if not imgTable then
   status="error"
   errtype="No opened file"
  else
   status="requesting"
   rqstr=imgName
   requested="Save as"
  end
 end
end

function setColor(action)
 if action=="h" then
  status="requesting"
  rqstr=""
  requested="Hex code"
 elseif action=="s" then
  status="selectingColor"
  selColor=1
  newColor={math.floor(color[1]/5)*5,math.floor(color[2]/5)*5,math.floor(color[3]/5)*5}
 end
end

function setZoom(action)
 if action=="+" then --Zoom in
  if imgZoom<8 then
   xScroll=0
   yScroll=0
   imgZoom=imgZoom*2
  end
 elseif action=="-" then --Zoom out
  if imgZoom>1 then
   xScroll=0
   yScroll=0
   imgZoom=imgZoom/2
  end
 end
end

function selectTool(action)
 toolStep=1
 if action=="d" then
  tool="draw"
 elseif action=="e" then
  tool="erase"
 elseif action=="f" then
  tool="fill"
 elseif action=="p" then
  tool="pick"
 elseif action=="c" then
  tool="circle"
 elseif action=="l" then
  tool="line"
 elseif action=="r" then
  tool="rect"
 end
end

toolAction={}

function toolAction.draw()
 imgTable[xPos][yPos]={1,math.floor(color[1]/8),math.floor(color[2]/8),math.floor(color[3]/8)}
 changedMark="*"
end

function toolAction.erase()
 imgTable[xPos][yPos][1]=0
 changedMark="*"
end

function toolAction.pick()
 if imgTable[xPos][yPos][1]==0 then
  color={255,255,255}
 else
  color={imgTable[xPos][yPos][2]*8,imgTable[xPos][yPos][3]*8,imgTable[xPos][yPos][4]*8}
 end
end

function toolAction.fill()
 fillPixel(xPos,yPos)
end

function toolAction.rect()
 if toolStep==1 then
  toolStep=2
  step1.x,step1.y=xPos,yPos
 else
  toolStep=1
  drawRect(step1.x,step1.y,xPos,yPos)
 end
end

function toolAction.circle()
 if toolStep==1 then
  toolStep=2
  step1.x,step1.y=xPos,yPos
 else
  toolStep=1
  drawCircle(step1.x,step1.y,xPos,yPos)
 end
end

function toolAction.line()
 if toolStep==1 then
  toolStep=2
  step1.x,step1.y=xPos,yPos
 else
  toolStep=1
  drawLine(step1.x,step1.y,xPos,yPos)
 end
end

function requestAction()
 if requested=="Hex code" then
  loadHexColor()
 elseif requested=="Image width" then
  if tonumber(rqstr) and tonumber(rqstr)~=0 then
   tempVarWidth=tonumber(rqstr)
   status="requesting"
   requested="Image height"
   rqstr=""
  else
   status="error"
   errtype="Invalid number"
  end
 elseif requested=="Image height" then
  if tonumber(rqstr) and tonumber(rqstr)~=0 then
   if tonumber(rqstr)*tempVarWidth>3000 then
    status="error"
    errtype="Overflow (3000 px max)"
   else
    file.new()
   end
  else
   status="error"
   errtype="Invalid number"
  end
 elseif requested=="File name" then
  rqstr=string.lower(rqstr)
  file.load()
 elseif requested=="Save as" then
  rqstr=string.lower(rqstr)
  file.save()
 end
end

Data.lua
Spoiler For Spoiler:
Code: [Select]
--DATA
--drawing
status="drawing"
tool=nil
xPos=1
yPos=1
xScroll=0
yScroll=0
color={225,170,0}
changedMark=""
--image
imgString=nil
imgTable=nil
imgZoom=1
imgName=""
--color select
newColor={200,100,255}
selColor=1
--text request
requested=""
rqstr=""
--error
errtype=""
--tools
toolStep=1
step1={x=1,y=1}
--tools sprites - 1:move  2:draw  3:erase  4:pick  5:fill  6:circle  7:line  8:rect
toolsSprites={}
toolsSprites.move=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202_\202_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128_\202\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\000\128\255\255\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\255\255\255\255\000\128\000\128\000\128_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202\000\128\255\255\000\128\000\128\255\255\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\255\255\255\255\000\128\000\128\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128_\202\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202_\202_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.draw=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\011\202N\218-\214-\210\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\167\193p\230Z\255\148\254h\225e\185\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\234\197\145\222Y\255\148\254\140\253\164\240\001\173\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\167\189L\214\024\227\247\226\173\249\132\252$\209\012\202\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\168\193(\214\206\238h\230\213\218\239\229\226\208\234\197\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\168\193\008\210\238\238g\234#\226*\210\202\209\200\193\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\200\193\231\205\238\242h\234$\226\162\201B\185\168\193\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\200\193\231\205\238\242\136\234#\226\162\201\034\185\201\197\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\168\193\231\205\238\242\136\234#\226\162\201!\181\234\197\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\167\193\007\210\238\242\136\234#\226\162\201!\181\011\202\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\167\189(\214\238\238\136\234$\226\162\201!\181\011\202\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\012\202)\210\204\238g\234$\226\162\201!\181\235\201\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\134\189\240\230u\243\170\234\130\197B\185\202\197\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\232\201\016\235S\243\016\239A\185\168\193\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\012\202\144\214\208\230\008\210#\181\234\197\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\168\193\167\193e\185O\210\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\000\128\255\255\255\255\000\128\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.erase=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255y\182\215\157\215\157\214\157\214\157\214\157\214\157\214\157\181\157\180\153z\190\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255y\186\215\157\028\215\219\206\219\202\219\202\219\202\219\202\219\202\219\202\219\202/\149Y\182\255\255\000\128\000\128\255\255\255\255\255\255\219\202\215\157<\219\187\198\187\198\187\198\187\198\187\198\187\198\187\198\186\198\028\215\154\190Q\149\255\255\000\128\000\128\255\255\255\255\255\255P\149<\219\219\202\187\198\187\198\187\198\187\198\187\198\187\198\187\198\187\198\028\215\024\170Q\149\255\255\000\128\000\128\255\255\255\255P\149<\219<\219\180\238\180\238\180\242\180\242\180\242\180\242\180\242\147\242\028\215\187\198\024\170Q\149\255\255\000\128\000\128\255\255\255\255\173\245\023\247\180\242\180\242\180\242\180\242\180\242\180\242\180\242\147\242\180\242\023\243r\242\024\170Q\149\255\255\000\128\000\128\255\255\238\245r\246\214\242\180\238\180\242\180\242\180\242\180\242\180\242\180\242\147\242\213\242\147\246r\242Q\149\255\255\255\255\000\128\000\128\255\255Q\246\024\247\180\242\180\242\180\242\148\242\148\242\148\242\147\242\147\242\180\242\246\242r\242\015\242Q\149\255\255\255\255\000\128\000\128\255\255\239\245\246\242\180\242\180\242\180\242\180\242\148\242\147\242\148\246\147\246\181\246\214\246r\246\198\248\255\255\255\255\255\255\000\128\000\128\255\255\238\2459\2478\2518\2518\2518\2518\2518\2518\2518\251\023\251R\250\173\245)\237\255\255\255\255\255\255\000\128\000\128\255\255\140\245\016\254\207\253\239\253\239\253\239\253\239\253\239\253\239\253\239\253\206\253\206\249\231\244\255\255\255\255\255\255\255\255\000\128\000\128\255\255k\245R\2501\2501\2501\2501\2501\2501\2501\2501\2501\250\140\249(\233\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\198\248\166\248\198\248\198\248\198\248\198\248\198\248\198\248\198\248\198\248\198\244\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.pick=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\232\148.\153+\157k\173\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\198\148r\153O\153\232\148\166\148\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\2550\194J\169m\165\010\149O\153\199\148\198\148\165\144\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\007\161r\149\199\148\199\148\165\144\008\157\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255r\206\189\247)\161\198\148\199\152\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\147\210Z\235\157\239:\227\231\152\231\152\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\180\2149\231\190\243\249\2181\198\255\255)\161\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\180\214\182\206<\223\151\202R\202\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\180\2144\186\215\161r\149\017\190\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\179\214U\186\247\161\147\1532\194\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\147\210V\190\214\161\147\1532\194\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\015\194\182\157\148\1531\194\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255r\206\026\223\240\1891\194\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\210\169\240\185\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\2551\198\212\165n\161\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\018\1867\178n\161\175\173\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\2552\194\217\206X\182\246\169\011\153\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\2552\1947\178X\178\147\157L\161\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.fill=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\147\210Q\202\146\210r\2060\198\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\246\222Q\202\255\255\255\255\255\255\255\255\173\181\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\245\222\139\177Q\202R\202\180\214\255\255\139\177\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\2557\231\172\1811\198\156\243\223\255\206\185\255\255\139\177\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255Q\206\239\189\148\210R\202Z\235{\239Y\231Q\202\140\177\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\246\222\173\181\247\222\255\255\214\2181\198Z\235\024\227\222\251\016\194\139\177\255\255\255\255\255\255\000\128\000\128\255\255\000\240\000\2401\242\016\190\255\255\255\255\222\251\148\2100\198Z\2359\231Z\235\189\247k\173\255\255\255\255\255\255\000\128\000\1281\2421\242\206\1859\231\255\255\222\251\255\255\247\222\140\177\140\177\148\2109\231\024\227\189\247\147\206\212\218\255\255\255\255\000\128\000\128\000\2401\242\023\227\222\251{\239\189\247\189\247\173\181\016\194R\202\173\181\247\222Z\2359\231\222\251\015\190\255\255\255\255\000\128\000\128\000\2401\242\015\194\156\243{\239\156\243\156\243\173\181R\202\148\210\206\185\024\227Z\2359\231{\2398\231Q\202\255\255\000\128\000\128\000\2401\242\212\218s\206\189\247Z\235\156\243\246\218\206\185\206\185\148\210{\239{\239Z\2359\231\156\243r\206\245\222\000\128\000\128\000\2401\242\255\255\238\189\156\243{\239{\239\189\247{\239{\239\156\243\156\243{\239Z\2359\231Z\235Y\231\172\181\000\128\000\128\000\2401\242\255\255\255\255\239\189\255\255Z\235\156\243\255\255\255\255\222\251\189\247\156\243{\239Z\235\189\2479\231j\173\000\128\000\128\000\2401\242\255\255\255\255P\1989\231\156\243{\239\189\247\255\255\222\251\189\247\156\243\156\243\255\255\247\222\206\185\255\255\000\128\000\128\000\240\255\255\255\255\255\255\255\255\173\181\255\255Z\235\156\243\222\251\255\255\222\251\222\251\189\247\238\189\146\210\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\179\214\214\218\189\247{\239\189\247\255\255\222\251\181\214\238\189\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\205\185\156\243\156\243\156\2439\231\239\189\146\210\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255s\206\255\255\148\210\205\185\180\214\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.circle=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\031\130\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\000\128\000\128\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\000\128\000\128\255\255\031\130\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\031\130\255\255\255\255\000\128\000\128\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\000\128\000\128\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\000\128\000\128\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\031\130\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.line=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.rect=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\000\128\000\128\000\128\000\128\000\128\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\000\128\000\128\000\128\000\128\000\128\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")


--MENU
menu={
{"File",
 {"New (Shift+n)",function() menuAction("N") end},
 {"Open (Shift+o)",function() menuAction("O") end},
 {"Save (Shift+s)",function() menuAction("S") end}
},
{"Edit",
 {"Zoom in (+)",function() menuAction("+") end},
 {"Zoom out (-)",function() menuAction("-") end}
},
{"Tools",
 {"Draw (d)",function() menuAction("d") end},
 {"Erase (e)",function() menuAction("e") end},
 {"Fill (f)",function() menuAction("f") end},
 {"Color Pick (p)",function() menuAction("p") end},
 {"Circle (c)",function() menuAction("c") end},
 {"Line (l)",function() menuAction("l") end},
 {"Rectangle (r)",function() menuAction("r") end}
},
{"Color",
 {"Hexadecimal (h)",function() menuAction("h") end},
 {"Select (s)",function() menuAction("s") end}
}}
toolpalette.register(menu)
imgTools.lua
Spoiler For Spoiler:
Code: [Select]
imgTools={}

function imgTools.getPixel(byte1,byte2)
 local str2
 str2=imgTools.addZeros(mathTools.base10to2(tonumber(byte2)),8)..imgTools.addZeros(mathTools.base10to2(tonumber(byte1)),8)
 return {tonumber(string.sub(str2,1,1)),mathTools.base2to10(string.sub(str2,2,6)),mathTools.base2to10(string.sub(str2,7,11)),mathTools.base2to10(string.sub(str2,12,16))}
end

function imgTools.getSize(img)
 imgWidth=mathTools.base2to10(mathTools.base10to2(tonumber(string.sub(img,10,12)..string.sub(img,7,9)..string.sub(img,4,6)..string.sub(img,1,3))))
 imgHeight=mathTools.base2to10(mathTools.base10to2(tonumber(string.sub(img,22,24)..string.sub(img,19,21)..string.sub(img,16,18)..string.sub(img,13,15))))
end

function imgTools.addZeros(str,strSize)
 return string.rep("0",strSize-string.len(str))..str
end

function imgTools.convertChars(img)
 local finished,img2,index
 index=1
 img2=""
 finished=nil
 while not finished do
  if string.sub(img,index,index)~=[[\]] then
   img2=img2..imgTools.addZeros(tostring(string.byte(string.sub(img,index,index))),3)
   index=index+1
  else
   img2=img2..string.sub(img,index+1,index+3)
   index=index+4
  end
  if index>string.len(img) then
   finished=1
  end
 end
 return img2
end

function imgTools.generateHeader()
 local binaryHeader,header
 binaryHeader={}
 binaryHeader[1]=imgTools.addZeros(mathTools.base10to2(imgWidth),32)
 binaryHeader[2]=imgTools.addZeros(mathTools.base10to2(imgHeight),32)
 binaryHeader[3]=imgTools.addZeros(mathTools.base10to2(imgWidth*2),32)
 header={"","",""}
 for i=1,3 do
  for j=3,0,-1 do
   header[i]=header[i]..imgTools.addZeros(tostring(mathTools.base2to10(string.sub(binaryHeader[i],8*j+1,8*(j+1)))),3)
  end
 end
 return header[1]..header[2].."000000000000"..header[3].."016000001000"
end

function imgTools.convertPixel(pixel)
 local str
 str=tostring(pixel[1])..imgTools.addZeros(mathTools.base10to2(pixel[2]),5)..imgTools.addZeros(mathTools.base10to2(pixel[3]),5)..imgTools.addZeros(mathTools.base10to2(pixel[4]),5)
 return imgTools.addZeros(tostring(mathTools.base2to10(string.sub(str,9,16))),3)..imgTools.addZeros(tostring(mathTools.base2to10(string.sub(str,1,8))),3)
end

function imgTools.addSlashes(str)
 local finished,str2,index
 finished=nil
 str2=[[\]]..str
 index=1
 while not finished do
  index=index+4
  if index>string.len(str2) then
   finished=1
  else
   str2=string.sub(str2,1,index-1)..[[\]]..string.sub(str2,index)
  end
 end
 return str2
end

function imgTools.img2table(str)
 local index
 str2=imgTools.convertChars(str)
 imgTable={}
 imgTools.getSize(str2)
 for i=1,imgWidth do
  imgTable[i]={}
  for j=1,imgHeight do
   index=(i-1)*6+61+(j-1)*6*imgWidth
   imgTable[i][j]=imgTools.getPixel(string.sub(str2,index,index+2),string.sub(str2,index+3,index+5))
  end
 end
end

function imgTools.drawTable(gc,x,y)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","dashed")
 gc:drawRect(x-1,y-1,imgWidth*imgZoom+1,imgHeight*imgZoom+1)
 gc:setPen("thin","smooth")
 for i=1,imgWidth do
  for j=1,imgHeight do
   if imgTable[i][j][1]==1 then
    gc:setColorRGB(imgTable[i][j][2]*8,imgTable[i][j][3]*8,imgTable[i][j][4]*8)
    gc:fillRect((i-1)*imgZoom+x,(j-1)*imgZoom+y,imgZoom,imgZoom)
   else
    gc:setColorRGB(175,175,175)
    for k=0,imgZoom-1 do
     gc:fillRect((i-1)*imgZoom+x+k,(j-1)*imgZoom+y+k,1,1)
    end
   end
  end
 end
end

function imgTools.table2img()
 local imgStr
 imgStr=imgTools.generateHeader()
 for i=1,imgHeight do
  for j=1,imgWidth do
   imgStr=imgStr..imgTools.convertPixel(imgTable[j][i])
  end
 end
 return imgTools.addSlashes(imgStr)
end


Functions.lua
Spoiler For Spoiler:
Code: [Select]
--MATHTOOLS
mathTools={}

function mathTools.base10to2(n)
 local str
 str=""
 if n~=0 then
  while n~=1 do
   str=str..tostring(n%2)
   n=math.floor(n/2)
  end
  str=str..tostring(n%2)
  return string.reverse(str)
 else
  return "0"
 end
end

function mathTools.base2to10(n)
 local num = 0
 local ex = string.len(n) - 1
 local l = 0
 l = ex + 1
 for i = 1, l do
  b = string.sub(n, i, i)
  if b == "1" then
   num = num + 2^ex
  end
  ex = ex - 1
 end
 return num
end

function mathTools.int2Hex(int)
 if int<10 then
  return tostring(int)
 else
  if int==10 then return "A"
  elseif int==11 then return "B"
  elseif int==12 then return "C"
  elseif int==13 then return "D"
  elseif int==14 then return "E"
  elseif int==15 then return "F"
  end
 end
end



--FILE

file={}

function file.save()
 if rqstr=="" then
  status="error"
  errtype="Please type a name"
 elseif string.find("0123456789",string.sub(rqstr,1,1)) then
  status="error"
  errtype="Invalid name"
 else
  imgString=imgTools.table2img()
  var.store(rqstr,imgString)
  imgName=rqstr
  changedMark=""
 end
end

function file.load()
 local test
 test=var.recall(rqstr)
 if not test then
  status="error"
  errtype="File does not exist"
 elseif type(test)~="string" then
  status="error"
  errtype="Invalid file"
 else
  imgZoom=1
  xPos=1
  yPos=1
  xScroll=0
  yScroll=0
  tool=nil
  changedMark=""
  imgString=test
  imgTools.img2table(imgString)
  imgName=rqstr
 end
end

function file.new()
 imgWidth=tempVarWidth
 imgHeight=tonumber(rqstr)
 imgZoom=1
 xPos=1
 yPos=1
 xScroll=0
 yScroll=0
 tool=nil
 changedMark=""
 imgName="unsaved"
 imgTable={}
 for i=1,imgWidth do
  imgTable[i]={}
  for j=1,imgHeight do
   imgTable[i][j]={0,0,0,0}
  end
 end
end





--MISCELLANEOUS

function width()
 return platform.window:width()
end

function height()
 return platform.window:height()
end

function refresh()
 platform.window:invalidate()
end

function copyTable(t)
  local t2 = {}
  for k,v in pairs(t) do
    t2[k] = v
  end
  return t2
end

function samePixels(px1,px2)
 if (px1[1]==px2[1] and px1[2]==px2[2] and px1[3]==px2[3] and px1[4]==px2[4]) or (px1[1]==0 and px2[1]==0) then
  return 1
 else
  return nil
 end
end

function fillPixel(x,y)
 local previousPixel,xTest,yTest
 previousPixel=copyTable(imgTable[x][y])
 if not samePixels(previousPixel,{1,math.floor(color[1]/8),math.floor(color[2]/8),math.floor(color[3]/8)}) then
  changedMark="*"
  imgTable[x][y]={1,math.floor(color[1]/8),math.floor(color[2]/8),math.floor(color[3]/8)}
  for i=1,4 do
   xTest=math.floor(i/2)-1+x
   yTest=(i==3 and 1 or 0)-(i==2 and 1 or 0)+y
   if xTest>0 and xTest<imgWidth+1 and yTest>0 and yTest<imgHeight+1 then
    if samePixels(previousPixel,imgTable[xTest][yTest]) then
     fillPixel(xTest,yTest)
    end
   end
  end
 end
end

function setPixel(x,y)
 if x>=1 and x<=imgWidth and y>=1 and y<=imgHeight then
  imgTable[x][y]={1,math.floor(color[1]/8),math.floor(color[2]/8),math.floor(color[3]/8)}
 end
end

function drawCircle(x1,y1,x2,y2)
 local rayon=math.floor(math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)))
 local x,y,m
 x=0
 y=rayon
 m=5-4*rayon
 while x<=y do
  setPixel(x+x1,y+y1)
  setPixel(y+x1,x+y1)
  setPixel(-x+x1,y+y1)
  setPixel(-y+x1,x+y1)
  setPixel(x+x1,-y+y1)
  setPixel(y+x1,-x+y1)
  setPixel(-x+x1,-y+y1)
  setPixel(-y+x1,-x+y1)
  if m>0 then
   y=y-1
   m=m-8*y
  end
  x=x+1
  m=m+8*x+4
 end
end

function round(nb)
 if nb>math.floor(nb)+0.5 then
  return math.floor(nb)+1
 else
  return math.floor(nb)
 end
end

function drawLine(x1,y1,x2,y2)
 local reversed=nil
 if x1>x2 then
  x1,x2=x2,x1
  reversed=not reversed
 end
 if y1>y2 then
  y1,y2=y2,y1
  reversed=not reversed
 end
 local size=x2-x1>y2-y1 and x2-x1 or y2-y1
 for i=0,size do
  if reversed then
   setPixel(x1+(x2-x1)-round((i/size)*(x2-x1)),y1+round((i/size)*(y2-y1)))
  else
   setPixel(x1+round((i/size)*(x2-x1)),y1+round((i/size)*(y2-y1)))
  end
 end
end

function drawRect(x1,y1,x2,y2)
 if x1>x2 then
  x1,x2=x2,x1
 end
 if y1>y2 then
  y1,y2=y2,y1
 end
 for i=x1,x2 do
  setPixel(i,y1)
  setPixel(i,y2)
 end
 for i=y1,y2 do
  setPixel(x1,i)
  setPixel(x2,i)
 end
end

function loadHexColor()
 local isHex,tmptable
 isHex=1
 tmptable={}
 if string.len(rqstr)==6 then
  for i=1,6,1 do
   currentch=string.sub(rqstr,i,i)
   tmptable[i]=tonumber(currentch,16)
   if not tmptable[i] then
    isHex=nil
   end
  end
 else isHex=nil
 end
 if isHex then
  color={tmptable[1]*16+tmptable[2],tmptable[3]*16+tmptable[4],tmptable[5]*16+tmptable[6]}
 else
  status="error"
  errtype="Invalid hexadecimal"
 end
end


Drawing.lua
Spoiler For Spoiler:
Code: [Select]

--DRAWING
function drawColorSelect(gc)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-50,150,100)
 gc:setColorRGB(0,0,0)
 gc:fillRect(width()/2-75,height()/2-50,150,15)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-50,150,100)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString("Select your color",width()/2-73,height()/2-53,"top")
 gc:setColorRGB(0,0,0)
 gc:drawString("Red :",width()/2-73,height()/2-35,"top")
 gc:drawString("Green :",width()/2-73,height()/2-20,"top")
 gc:drawString("Blue :",width()/2-73,height()/2-5,"top")
 for i=0,63 do
  gc:setColorRGB(i*4,newColor[2],newColor[3])
  gc:fillRect(width()/2-23+i,height()/2-30,1,10)
  gc:setColorRGB(newColor[1],i*4,newColor[3])
  gc:fillRect(width()/2-23+i,height()/2-15,1,10)
  gc:setColorRGB(newColor[1],newColor[2],i*4)
  gc:fillRect(width()/2-23+i,height()/2,1,10)
 end
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-23,height()/2-46+selColor*15,64,11)
 for i=1,3 do
  gc:drawString(tostring(newColor[i]),width()/2+52,height()/2-50+i*15,"top")
  gc:fillRect(width()/2-24+newColor[i]/4,height()/2-47+i*15,3,14)
 end
 gc:setColorRGB(color[1],color[2],color[3])
 gc:fillRect(width()/2-70,height()/2+20,30,20)
 gc:setColorRGB(newColor[1],newColor[2],newColor[3])
 gc:fillRect(width()/2-28,height()/2+20,30,20)
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-70,height()/2+20,30,20)
 gc:drawRect(width()/2-28,height()/2+20,30,20)
 gc:drawString(mathTools.int2Hex(math.floor(newColor[1]/16))..mathTools.int2Hex(newColor[1]%16)..mathTools.int2Hex(math.floor(newColor[2]/16))..mathTools.int2Hex(newColor[2]%16)..mathTools.int2Hex(math.floor(newColor[3]/16))..mathTools.int2Hex(newColor[3]%16),width()/2+20,height()/2+20,"top")
 gc:drawString("Old     New",width()/2-65,height()/2+21,"top")
end

function drawRequest(gc,msg)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-25,150,50)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-25,150,50)
 gc:fillRect(width()/2-75,height()/2-25,150,15)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString(msg,width()/2-70,height()/2-28,"top")
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-70,height()/2,140,20)
 gc:drawString(rqstr,width()/2-65,height()/2,"top")
end

function drawError(gc)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-20,150,40)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-20,150,40)
 gc:fillRect(width()/2-75,height()/2-20,150,15)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString("Error",width()/2-73,height()/2-23,"top")
 gc:setColorRGB(0,0,0)
 gc:drawString(errtype,width()/2-70,height()/2-5,"top")
end

function drawCursor(gc)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect((xPos-1)*imgZoom+29-xScroll*imgZoom,(yPos-1)*imgZoom+29-yScroll*imgZoom,imgZoom+1,imgZoom+1)
 gc:setColorRGB(255,255,255)
 gc:drawRect((xPos-1)*imgZoom+30-xScroll*imgZoom,(yPos-1)*imgZoom+30-yScroll*imgZoom,imgZoom-1,imgZoom-1)
end

function drawTool(gc)
 local id=tool
 if not id then
  id="move"
 end
 gc:drawImage(toolsSprites[id],0,15)
end

drawStep1={}

function drawStep1.circle(gc)
 local rayon=math.sqrt((xPos-step1.x)*(xPos-step1.x)+(yPos-step1.y)*(yPos-step1.y))
 local startX,startY,size
 startX,startY=(step1.x-rayon-0.6)*imgZoom+30-xScroll*imgZoom,(step1.y-rayon-0.6)*imgZoom+30-yScroll*imgZoom
 size=2*rayon*imgZoom
 gc:setColorRGB(255,255,255)
 gc:drawArc(startX-1,startY-1,size,size,0,360)
 gc:setColorRGB(0,0,0)
 gc:drawArc(startX,startY,size,size,0,360)
end

function drawStep1.line(gc)
 gc:setColorRGB(255,255,255)
 gc:drawLine((step1.x-0.6)*imgZoom+30-xScroll*imgZoom,(step1.y-0.6)*imgZoom+30-yScroll*imgZoom,(xPos-0.6)*imgZoom+30-xScroll*imgZoom,(yPos-0.6)*imgZoom+30-yScroll*imgZoom)
 gc:setColorRGB(0,0,0)
 gc:drawLine((step1.x-0.6)*imgZoom+29-xScroll*imgZoom,(step1.y-0.6)*imgZoom+29-yScroll*imgZoom,(xPos-0.6)*imgZoom+29-xScroll*imgZoom,(yPos-0.6)*imgZoom+29-yScroll*imgZoom)
end

function drawStep1.rect(gc)
 local startX,startY,sizeX,sizeY,lowerY,higherY
 lowerX,lowerY=xPos<step1.x and xPos or step1.x,yPos<step1.y and yPos or step1.y
 startX,startY=(lowerX-0.6)*imgZoom+30-xScroll*imgZoom,(lowerY-0.6)*imgZoom+30-yScroll*imgZoom
 sizeX,sizeY=math.abs((xPos-step1.x)*imgZoom),math.abs((yPos-step1.y)*imgZoom)
 gc:setColorRGB(255,255,255)
 gc:drawRect(startX-1,startY-1,sizeX,sizeY)
 gc:setColorRGB(0,0,0)
 gc:drawRect(startX,startY,sizeX,sizeY)
end

function drawStep1.start(gc)
 local x,y=(step1.x-1)*imgZoom+29-xScroll*imgZoom,(step1.y-1)*imgZoom+29-yScroll*imgZoom
 gc:setColorRGB(255,255,255)
 gc:drawLine(x-1,y,x+imgZoom-1,y+imgZoom)
 gc:drawLine(x+imgZoom-1,y,x-1,y+imgZoom)
 gc:setColorRGB(0,0,0)
 gc:drawLine(x,y,x+imgZoom,y+imgZoom)
 gc:drawLine(x+imgZoom,y,x,y+imgZoom)
end

function on.paint(gc)
 if imgTable then
  imgTools.drawTable(gc,30-xScroll*imgZoom,30-yScroll*imgZoom)
  if tool then
   drawCursor(gc)
   if toolStep==2 then
    drawStep1[tool](gc)
    drawStep1.start(gc)
   end
  end
 end
 gc:setColorRGB(color[1],color[2],color[3])
 gc:fillRect(0,0,20,15)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(0,0,19,15)
 drawTool(gc)
 gc:setFont("sansserif","r",10)
 if imgTable then
  gc:drawString(changedMark..imgName.." - "..tostring(imgWidth).."x"..tostring(imgHeight).." ("..tostring(imgZoom*100).."%)",25,0,"top")
 else
  gc:drawString("Open or create a file",25,0,"top")
 end
 if status=="selectingColor" then
  drawColorSelect(gc)
 elseif status=="requesting" then
  drawRequest(gc,requested)
 elseif status=="error" then
  drawError(gc)
 end
 gc:setColorRGB(0,0,0)
 gc:setFont("sansserif","r",8)
 gc:drawString("Lua nSpaint - Par Loic Pujet",10,height()-12,"top")
end
Events.lua
Spoiler For Spoiler:
Code: [Select]
--EVENTS
function on.backspaceKey()
 if status=="requesting" then
  rqstr=string.sub(rqstr,1,string.len(rqstr)-1)
  platform.window:invalidate()
 end
end

function on.charIn(ch)
 if status=="drawing" then
  if string.find("NOS+-defphsclr",ch) then
   menuAction(ch)
  end
 elseif status=="requesting" and string.len(rqstr)<10 and string.find("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",ch) then
  rqstr=rqstr..ch
 end
 refresh()
end

function on.escapeKey()
 if status=="drawing" then
  tool=nil
 else
  status="drawing"
 end
 refresh()
end

function on.enterKey()
 if status=="drawing" and tool and imgTable then
  toolAction[tool]()
 elseif status=="selectingColor" then
  color=newColor
  status="drawing"
 elseif status=="requesting" then
  status="drawing"
  requestAction()
 elseif status=="error" then
  status="drawing"
 end
 refresh()
end

function on.arrowKey(ar)
 if status=="drawing" and imgTable then
  if tool then
   if ar=="up" and yPos>1 then yPos=yPos-1 end
   if ar=="down" and yPos<imgHeight then yPos=yPos+1 end
   if ar=="left" and xPos>1 then xPos=xPos-1 end
   if ar=="right" and xPos<imgWidth then xPos=xPos+1 end
  else
   if ar=="down" and (imgHeight-yScroll)*imgZoom>height()-45 then yScroll=yScroll+1 end
   if ar=="up" and yScroll>0 then yScroll=yScroll-1 end
   if ar=="right" and (imgWidth-xScroll)*imgZoom>width()-45 then xScroll=xScroll+1 end
   if ar=="left" and xScroll>0 then xScroll=xScroll-1 end
  end
 elseif status=="selectingColor" then
  if ar=="up" then
   selColor=selColor-1
  elseif ar=="down" then
   selColor=selColor+1
  elseif ar=="right" and newColor[selColor]<251 then
   newColor[selColor]=newColor[selColor]+5
  elseif ar=="left" and newColor[selColor]>4 then
   newColor[selColor]=newColor[selColor]-5
  end
  if selColor>3 then
   selColor=1
  elseif selColor<1 then
   selColor=3
  end
 end
 refresh()
end

function on.resize()
 xScroll=0
 yScroll=0
end

I attach screenies and the TNS file
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on September 12, 2011, 03:17:47 pm
Very nice :)
Title: Re: [Lua] Image Editor
Post by: pianoman on September 12, 2011, 05:35:59 pm
Nice job :)
Title: Re: [Lua] Image Editor
Post by: Yeong on September 12, 2011, 05:38:27 pm
good work XD
Title: Re: [Lua] Image Editor
Post by: DJ Omnimaga on October 23, 2011, 08:26:43 pm
I should really install this on my calc and give it a try eventually. Does it work on OS 3.0.1?
Title: Re: [Lua] Image Editor
Post by: Chockosta on October 25, 2011, 06:02:57 am
It should...
(Make sure you download the latest version (http://www.omnimaga.org/index.php?action=dlattach;topic=9821.0;attach=9397))

By the way, I should get back to this project which was paused for a while
Title: Re: [Lua] Image Editor
Post by: AzNg0d1030 on October 26, 2011, 10:09:51 pm
If I download the latest version and put it on my calculator, will my previous work that was on the previous version be deleted?  Or is it actually stored somewhere so it'll be fine?

And if it is stored, is there any way to view it out of nSpaint?
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on October 27, 2011, 02:54:30 am
If you actually replaced the file on your calculator, they will be gone. If you have the both files on your calculator (with a different name), you still can get your work out.
Title: Re: [Lua] Image Editor
Post by: Scipi on October 27, 2011, 01:15:05 pm
Hmm. Is there a way to make it so the images can be stored as separate files or made to be accessible outside of the nSpaint document? Or is that already implemented?

(I really should update the version on my calc and start working some more on some of my projects [I need to finish at least one of them] T_T) :P
Title: Re: [Lua] Image Editor
Post by: Adriweb on October 27, 2011, 01:16:29 pm
You can copy your variables out and paste them in an external document I guess....
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on October 27, 2011, 01:35:58 pm
You could add an "export" button which puts the data in the clipboard, and then you would open another "save" file which has an import function (fetches out of the clipboard). You can then easily read the data then if the save file is a library document (using math.eval). Sad thing that you can't edit them :(
Title: Re: [Lua] Image Editor
Post by: Chockosta on October 29, 2011, 02:15:00 pm
That's a really good idea...

Thanks !
Title: Re: [Lua] Image Editor
Post by: Chockosta on October 30, 2011, 01:10:58 pm
Update !

Nspaint 0.6

-fill rectangle tool
-fill circle tool
-flip image (horizontally or vertically)
-rotate image (90ยฐ clockwise or counter-clockwise)
-filters !
-invert colors filter
-random colors filter

DOWNLOAD (http://www.omnimaga.org/index.php?action=dlattach;topic=9821.0;attach=10121)

Code : (now 1000 lines)

Spoiler For Spoiler:
actions.lua
Spoiler For Spoiler:
Code: [Select]
--MISC ACTIONS

function menuShortcut(action)
 if string.find("NOS",action) then
  fileAction(action)
 elseif string.find("+-",action) then
  setZoom(action)
 elseif string.find("defpclr",action) then
  selectTool(action)
 elseif string.find("hs",action) then
  setColor(action)
 end
 refresh()
end

function fileAction(action)
 if action=="N" then
  status="requesting"
  rqstr=""
  requested="Image width"
 elseif action=="O" then
  status="requesting"
  rqstr=""
  requested="File name"
 elseif action=="S" then
  if not imgTable then
   status="error"
   errtype="No opened file"
  else
   status="requesting"
   rqstr=imgName
   requested="Save as"
  end
 end
 refresh()
end

function setColor(action)
 if action=="h" then
  status="requesting"
  rqstr=""
  requested="Hex code"
 elseif action=="s" then
  status="selectingColor"
  selColor=1
  newColor={math.floor(color[1]/5)*5,math.floor(color[2]/5)*5,math.floor(color[3]/5)*5}
 end
 refresh()
end

function setZoom(action)
 if action=="+" then --Zoom in
  if imgZoom<8 then
   xScroll=0
   yScroll=0
   imgZoom=imgZoom*2
  end
 elseif action=="-" then --Zoom out
  if imgZoom>1 then
   xScroll=0
   yScroll=0
   imgZoom=imgZoom/2
  end
 end
 refresh()
end

function applyFilter(filterID)

end

function selectTool(toolID)
 toolStep=1
 if toolID=="d" then
  tool="draw"
 elseif toolID=="e" then
  tool="erase"
 elseif toolID=="f" then
  tool="fill"
 elseif toolID=="p" then
  tool="pick"
 elseif toolID=="c" then
  tool="circle"
 elseif toolID=="l" then
  tool="line"
 elseif toolID=="r" then
  tool="rect"
 elseif toolID=="fr" then
  tool="frect"
 elseif toolID=="fc" then
  tool="fcircle"
 end
 refresh()
end

toolAction={}

function toolAction.draw()
 imgTable[xPos][yPos]={1,math.floor(color[1]/8),math.floor(color[2]/8),math.floor(color[3]/8)}
 changedMark="*"
end

function toolAction.erase()
 imgTable[xPos][yPos][1]=0
 changedMark="*"
end

function toolAction.pick()
 if imgTable[xPos][yPos][1]==0 then
  color={255,255,255}
 else
  color={imgTable[xPos][yPos][2]*8,imgTable[xPos][yPos][3]*8,imgTable[xPos][yPos][4]*8}
 end
end

function toolAction.fill()
 fillPixel(xPos,yPos)
end

function toolAction.rect()
 if toolStep==1 then
  toolStep=2
  step1.x,step1.y=xPos,yPos
 else
  toolStep=1
  drawRect(step1.x,step1.y,xPos,yPos)
 end
end

function toolAction.circle()
 if toolStep==1 then
  toolStep=2
  step1.x,step1.y=xPos,yPos
 else
  toolStep=1
  drawCircle(step1.x,step1.y,xPos,yPos)
 end
end

function toolAction.line()
 if toolStep==1 then
  toolStep=2
  step1.x,step1.y=xPos,yPos
 else
  toolStep=1
  drawLine(step1.x,step1.y,xPos,yPos)
 end
end

function toolAction.frect()
 if toolStep==1 then
  toolStep=2
  step1.x,step1.y=xPos,yPos
 else
  toolStep=1
  fillRect(step1.x,step1.y,xPos,yPos)
 end
end

function toolAction.fcircle()
 if toolStep==1 then
  toolStep=2
  step1.x,step1.y=xPos,yPos
 else
  toolStep=1
  fillCircle(step1.x,step1.y,xPos,yPos)
 end
end

function requestAction()
 if requested=="Hex code" then
  loadHexColor()
 elseif requested=="Image width" then
  if tonumber(rqstr) and tonumber(rqstr)~=0 then
   tempVarWidth=tonumber(rqstr)
   status="requesting"
   requested="Image height"
   rqstr=""
  else
   status="error"
   errtype="Invalid number"
  end
 elseif requested=="Image height" then
  if tonumber(rqstr) and tonumber(rqstr)~=0 then
   if tonumber(rqstr)*tempVarWidth>3000 then
    status="error"
    errtype="Overflow (3000 px max)"
   else
    file.new()
   end
  else
   status="error"
   errtype="Invalid number"
  end
 elseif requested=="File name" then
  rqstr=string.lower(rqstr)
  file.load()
 elseif requested=="Save as" then
  rqstr=string.lower(rqstr)
  file.save()
 end
end

Data.lua
Spoiler For Spoiler:
Code: [Select]
--DATA
--drawing
status="drawing"
tool=nil
xPos=1
yPos=1
xScroll=0
yScroll=0
color={225,170,0}
changedMark=""
--image
imgString=nil
imgTable=nil
imgZoom=1
imgName=""
--color select
newColor={200,100,255}
selColor=1
--text request
requested=""
rqstr=""
--error
errtype=""
--tools
toolStep=1
step1={x=1,y=1}
--tools sprites
toolsSprites={}
toolsSprites.move=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202_\202_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128_\202\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\000\128\255\255\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\255\255\255\255\000\128\000\128\000\128_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202_\202\000\128\255\255\000\128\000\128\255\255\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\000\128\000\128\000\128\000\128_\202\000\128\255\255\255\255\000\128\000\128\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128_\202\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202_\202_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128_\202\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.draw=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\011\202N\218-\214-\210\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\167\193p\230Z\255\148\254h\225e\185\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\234\197\145\222Y\255\148\254\140\253\164\240\001\173\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\167\189L\214\024\227\247\226\173\249\132\252$\209\012\202\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\168\193(\214\206\238h\230\213\218\239\229\226\208\234\197\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\168\193\008\210\238\238g\234#\226*\210\202\209\200\193\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\200\193\231\205\238\242h\234$\226\162\201B\185\168\193\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\200\193\231\205\238\242\136\234#\226\162\201\034\185\201\197\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\168\193\231\205\238\242\136\234#\226\162\201!\181\234\197\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\167\193\007\210\238\242\136\234#\226\162\201!\181\011\202\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\167\189(\214\238\238\136\234$\226\162\201!\181\011\202\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\012\202)\210\204\238g\234$\226\162\201!\181\235\201\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\134\189\240\230u\243\170\234\130\197B\185\202\197\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\232\201\016\235S\243\016\239A\185\168\193\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\012\202\144\214\208\230\008\210#\181\234\197\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\168\193\167\193e\185O\210\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\000\128\255\255\255\255\000\128\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.erase=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255y\182\215\157\215\157\214\157\214\157\214\157\214\157\214\157\181\157\180\153z\190\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255y\186\215\157\028\215\219\206\219\202\219\202\219\202\219\202\219\202\219\202\219\202/\149Y\182\255\255\000\128\000\128\255\255\255\255\255\255\219\202\215\157<\219\187\198\187\198\187\198\187\198\187\198\187\198\187\198\186\198\028\215\154\190Q\149\255\255\000\128\000\128\255\255\255\255\255\255P\149<\219\219\202\187\198\187\198\187\198\187\198\187\198\187\198\187\198\187\198\028\215\024\170Q\149\255\255\000\128\000\128\255\255\255\255P\149<\219<\219\180\238\180\238\180\242\180\242\180\242\180\242\180\242\147\242\028\215\187\198\024\170Q\149\255\255\000\128\000\128\255\255\255\255\173\245\023\247\180\242\180\242\180\242\180\242\180\242\180\242\180\242\147\242\180\242\023\243r\242\024\170Q\149\255\255\000\128\000\128\255\255\238\245r\246\214\242\180\238\180\242\180\242\180\242\180\242\180\242\180\242\147\242\213\242\147\246r\242Q\149\255\255\255\255\000\128\000\128\255\255Q\246\024\247\180\242\180\242\180\242\148\242\148\242\148\242\147\242\147\242\180\242\246\242r\242\015\242Q\149\255\255\255\255\000\128\000\128\255\255\239\245\246\242\180\242\180\242\180\242\180\242\148\242\147\242\148\246\147\246\181\246\214\246r\246\198\248\255\255\255\255\255\255\000\128\000\128\255\255\238\2459\2478\2518\2518\2518\2518\2518\2518\2518\251\023\251R\250\173\245)\237\255\255\255\255\255\255\000\128\000\128\255\255\140\245\016\254\207\253\239\253\239\253\239\253\239\253\239\253\239\253\239\253\206\253\206\249\231\244\255\255\255\255\255\255\255\255\000\128\000\128\255\255k\245R\2501\2501\2501\2501\2501\2501\2501\2501\2501\250\140\249(\233\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\198\248\166\248\198\248\198\248\198\248\198\248\198\248\198\248\198\248\198\248\198\244\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.pick=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\232\148.\153+\157k\173\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\198\148r\153O\153\232\148\166\148\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\2550\194J\169m\165\010\149O\153\199\148\198\148\165\144\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\007\161r\149\199\148\199\148\165\144\008\157\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255r\206\189\247)\161\198\148\199\152\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\147\210Z\235\157\239:\227\231\152\231\152\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\180\2149\231\190\243\249\2181\198\255\255)\161\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\180\214\182\206<\223\151\202R\202\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\180\2144\186\215\161r\149\017\190\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\179\214U\186\247\161\147\1532\194\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\147\210V\190\214\161\147\1532\194\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\015\194\182\157\148\1531\194\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255r\206\026\223\240\1891\194\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\210\169\240\185\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\2551\198\212\165n\161\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\018\1867\178n\161\175\173\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\2552\194\217\206X\182\246\169\011\153\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\2552\1947\178X\178\147\157L\161\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.fill=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\147\210Q\202\146\210r\2060\198\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\246\222Q\202\255\255\255\255\255\255\255\255\173\181\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\245\222\139\177Q\202R\202\180\214\255\255\139\177\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\2557\231\172\1811\198\156\243\223\255\206\185\255\255\139\177\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255Q\206\239\189\148\210R\202Z\235{\239Y\231Q\202\140\177\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\246\222\173\181\247\222\255\255\214\2181\198Z\235\024\227\222\251\016\194\139\177\255\255\255\255\255\255\000\128\000\128\255\255\000\240\000\2401\242\016\190\255\255\255\255\222\251\148\2100\198Z\2359\231Z\235\189\247k\173\255\255\255\255\255\255\000\128\000\1281\2421\242\206\1859\231\255\255\222\251\255\255\247\222\140\177\140\177\148\2109\231\024\227\189\247\147\206\212\218\255\255\255\255\000\128\000\128\000\2401\242\023\227\222\251{\239\189\247\189\247\173\181\016\194R\202\173\181\247\222Z\2359\231\222\251\015\190\255\255\255\255\000\128\000\128\000\2401\242\015\194\156\243{\239\156\243\156\243\173\181R\202\148\210\206\185\024\227Z\2359\231{\2398\231Q\202\255\255\000\128\000\128\000\2401\242\212\218s\206\189\247Z\235\156\243\246\218\206\185\206\185\148\210{\239{\239Z\2359\231\156\243r\206\245\222\000\128\000\128\000\2401\242\255\255\238\189\156\243{\239{\239\189\247{\239{\239\156\243\156\243{\239Z\2359\231Z\235Y\231\172\181\000\128\000\128\000\2401\242\255\255\255\255\239\189\255\255Z\235\156\243\255\255\255\255\222\251\189\247\156\243{\239Z\235\189\2479\231j\173\000\128\000\128\000\2401\242\255\255\255\255P\1989\231\156\243{\239\189\247\255\255\222\251\189\247\156\243\156\243\255\255\247\222\206\185\255\255\000\128\000\128\000\240\255\255\255\255\255\255\255\255\173\181\255\255Z\235\156\243\222\251\255\255\222\251\222\251\189\247\238\189\146\210\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\179\214\214\218\189\247{\239\189\247\255\255\222\251\181\214\238\189\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\205\185\156\243\156\243\156\2439\231\239\189\146\210\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255s\206\255\255\148\210\205\185\180\214\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.circle=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\031\130\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\000\128\000\128\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\000\128\000\128\255\255\031\130\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\031\130\255\255\255\255\000\128\000\128\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\000\128\000\128\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\000\128\000\128\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\031\130\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.line=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.rect=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\000\128\000\128\000\128\000\128\000\128\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\000\128\000\128\000\128\000\128\000\128\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.frect=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\000\128\000\128\000\128\000\128\000\128\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\000\128\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\031\130\000\128\000\128\000\128\000\128\000\128\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")
toolsSprites.fcircle=image.new("\020\000\000\000\020\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\031\130\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\031\130\031\130\241\199\241\199\241\199\241\199\241\199\031\130\031\130\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\000\128\000\128\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\000\128\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\000\128\000\128\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\000\128\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\000\128\000\128\255\255\031\130\241\199\241\199\241\199\241\199\000\128\000\128\000\128\000\128\000\128\241\199\241\199\241\199\241\199\031\130\255\255\255\255\000\128\000\128\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\000\128\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\000\128\000\128\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\000\128\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\000\128\000\128\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\031\130\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\241\199\031\130\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\031\130\031\130\241\199\241\199\241\199\241\199\241\199\031\130\031\130\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\031\130\031\130\031\130\031\130\031\130\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128\000\128")

--MENU
menu={
{"File",
 {"New (Shift+n)",function() fileAction("N") end},
 {"Open (Shift+o)",function() fileAction("O") end},
 {"Save (Shift+s)",function() fileAction("S") end}
},
{"Edit",
 {"Zoom in (+)",function() setZoom("+") end},
 {"Zoom out (-)",function() setZoom("-") end},
 {"Erase all",function() eraseImg() end}
},
{"Tools",
 {"Draw (d)",function() selectTool("d") end},
 {"Erase (e)",function() selectTool("e") end},
 {"Fill (f)",function() selectTool("f") end},
 {"Color Pick (p)",function() selectTool("p") end},
 {"Circle (c)",function() selectTool("c") end},
 {"Line (l)",function() selectTool("l") end},
 {"Rectangle (r)",function() selectTool("r") end},
 {"Fill rectangle",function() selectTool("fr") end},
 {"Fill circle",function() selectTool("fc") end}
},
{"Color",
 {"Hexadecimal (h)",function() setColor("h") end},
 {"Select (s)",function() setColor("s") end}
},
{"Image",
 {"Flip vertically",function() flipV() end},
 {"Flip horizontally",function() flipH() end},
 {"Rotate 90ยฐ clockwise",function() rotateImg("c") end},
 {"Rotate 90ยฐ counter-clockwise",function() rotateImg("cc") end}
},
{"Filters",
 {"Invert colors",function() applyFilter("i") end},
 {"Random image", function() applyFilter("r") end}
}}
toolpalette.register(menu)
Drawing.lua
Spoiler For Spoiler:
Code: [Select]

--DRAWING
function drawColorSelect(gc)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-50,150,100)
 gc:setColorRGB(0,0,0)
 gc:fillRect(width()/2-75,height()/2-50,150,15)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-50,150,100)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString("Select your color",width()/2-73,height()/2-53,"top")
 gc:setColorRGB(0,0,0)
 gc:drawString("Red :",width()/2-73,height()/2-35,"top")
 gc:drawString("Green :",width()/2-73,height()/2-20,"top")
 gc:drawString("Blue :",width()/2-73,height()/2-5,"top")
 for i=0,63 do
  gc:setColorRGB(i*4,newColor[2],newColor[3])
  gc:fillRect(width()/2-23+i,height()/2-30,1,10)
  gc:setColorRGB(newColor[1],i*4,newColor[3])
  gc:fillRect(width()/2-23+i,height()/2-15,1,10)
  gc:setColorRGB(newColor[1],newColor[2],i*4)
  gc:fillRect(width()/2-23+i,height()/2,1,10)
 end
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-23,height()/2-46+selColor*15,64,11)
 for i=1,3 do
  gc:drawString(tostring(newColor[i]),width()/2+52,height()/2-50+i*15,"top")
  gc:fillRect(width()/2-24+newColor[i]/4,height()/2-47+i*15,3,14)
 end
 gc:setColorRGB(color[1],color[2],color[3])
 gc:fillRect(width()/2-70,height()/2+20,30,20)
 gc:setColorRGB(newColor[1],newColor[2],newColor[3])
 gc:fillRect(width()/2-28,height()/2+20,30,20)
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-70,height()/2+20,30,20)
 gc:drawRect(width()/2-28,height()/2+20,30,20)
 gc:drawString(mathTools.int2Hex(math.floor(newColor[1]/16))..mathTools.int2Hex(newColor[1]%16)..mathTools.int2Hex(math.floor(newColor[2]/16))..mathTools.int2Hex(newColor[2]%16)..mathTools.int2Hex(math.floor(newColor[3]/16))..mathTools.int2Hex(newColor[3]%16),width()/2+20,height()/2+20,"top")
 gc:drawString("Old     New",width()/2-65,height()/2+21,"top")
end

function drawRequest(gc,msg)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-25,150,50)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-25,150,50)
 gc:fillRect(width()/2-75,height()/2-25,150,15)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString(msg,width()/2-70,height()/2-28,"top")
 gc:setColorRGB(0,0,0)
 gc:drawRect(width()/2-70,height()/2,140,20)
 gc:drawString(rqstr,width()/2-65,height()/2,"top")
end

function drawError(gc)
 gc:setColorRGB(200,200,255)
 gc:fillRect(width()/2-75,height()/2-20,150,40)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(width()/2-75,height()/2-20,150,40)
 gc:fillRect(width()/2-75,height()/2-20,150,15)
 gc:setFont("sansserif","r",10)
 gc:setColorRGB(255,255,255)
 gc:drawString("Error",width()/2-73,height()/2-23,"top")
 gc:setColorRGB(0,0,0)
 gc:drawString(errtype,width()/2-70,height()/2-5,"top")
end

function drawCursor(gc)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect((xPos-1)*imgZoom+29-xScroll*imgZoom,(yPos-1)*imgZoom+29-yScroll*imgZoom,imgZoom+1,imgZoom+1)
 gc:setColorRGB(255,255,255)
 gc:drawRect((xPos-1)*imgZoom+30-xScroll*imgZoom,(yPos-1)*imgZoom+30-yScroll*imgZoom,imgZoom-1,imgZoom-1)
end

function drawTool(gc)
 local id=tool
 if not id then
  id="move"
 end
 gc:drawImage(toolsSprites[id],0,15)
end

drawStep1={}

function drawStep1.circle(gc)
 local rayon=math.sqrt((xPos-step1.x)*(xPos-step1.x)+(yPos-step1.y)*(yPos-step1.y))
 local startX,startY,size
 startX,startY=(step1.x-rayon-0.6)*imgZoom+30-xScroll*imgZoom,(step1.y-rayon-0.6)*imgZoom+30-yScroll*imgZoom
 size=2*rayon*imgZoom
 gc:setColorRGB(255,255,255)
 gc:drawArc(startX-1,startY-1,size,size,0,360)
 gc:setColorRGB(0,0,0)
 gc:drawArc(startX,startY,size,size,0,360)
end

function drawStep1.line(gc)
 gc:setColorRGB(255,255,255)
 gc:drawLine((step1.x-0.6)*imgZoom+30-xScroll*imgZoom,(step1.y-0.6)*imgZoom+30-yScroll*imgZoom,(xPos-0.6)*imgZoom+30-xScroll*imgZoom,(yPos-0.6)*imgZoom+30-yScroll*imgZoom)
 gc:setColorRGB(0,0,0)
 gc:drawLine((step1.x-0.6)*imgZoom+29-xScroll*imgZoom,(step1.y-0.6)*imgZoom+29-yScroll*imgZoom,(xPos-0.6)*imgZoom+29-xScroll*imgZoom,(yPos-0.6)*imgZoom+29-yScroll*imgZoom)
end

function drawStep1.rect(gc)
 local startX,startY,sizeX,sizeY,lowerY,higherY
 lowerX,lowerY=xPos<step1.x and xPos or step1.x,yPos<step1.y and yPos or step1.y
 startX,startY=(lowerX-0.6)*imgZoom+30-xScroll*imgZoom,(lowerY-0.6)*imgZoom+30-yScroll*imgZoom
 sizeX,sizeY=math.abs((xPos-step1.x)*imgZoom),math.abs((yPos-step1.y)*imgZoom)
 gc:setColorRGB(255,255,255)
 gc:drawRect(startX-1,startY-1,sizeX,sizeY)
 gc:setColorRGB(0,0,0)
 gc:drawRect(startX,startY,sizeX,sizeY)
end

function drawStep1.frect(gc)
 drawStep1.rect(gc)
end

function drawStep1.fcircle(gc)
 drawStep1.circle(gc)
end

function drawStep1.start(gc)
 local x,y=(step1.x-1)*imgZoom+29-xScroll*imgZoom,(step1.y-1)*imgZoom+29-yScroll*imgZoom
 gc:setColorRGB(255,255,255)
 gc:drawLine(x-1,y,x+imgZoom-1,y+imgZoom)
 gc:drawLine(x+imgZoom-1,y,x-1,y+imgZoom)
 gc:setColorRGB(0,0,0)
 gc:drawLine(x,y,x+imgZoom,y+imgZoom)
 gc:drawLine(x+imgZoom,y,x,y+imgZoom)
end

function on.paint(gc)
 if imgTable then
  imgTools.drawTable(gc,30-xScroll*imgZoom,30-yScroll*imgZoom)
  if tool then
   drawCursor(gc)
   if toolStep==2 then
    drawStep1[tool](gc)
    drawStep1.start(gc)
   end
  end
 end
 gc:setColorRGB(color[1],color[2],color[3])
 gc:fillRect(0,0,20,15)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","smooth")
 gc:drawRect(0,0,19,15)
 drawTool(gc)
 gc:setFont("sansserif","r",10)
 if imgTable then
  gc:drawString(changedMark..imgName.." - "..tostring(imgWidth).."x"..tostring(imgHeight).." ("..tostring(imgZoom*100).."%)",25,0,"top")
 else
  gc:drawString("Open or create a file",25,0,"top")
 end
 if status=="selectingColor" then
  drawColorSelect(gc)
 elseif status=="requesting" then
  drawRequest(gc,requested)
 elseif status=="error" then
  drawError(gc)
 end
 gc:setColorRGB(0,0,0)
 gc:setFont("sansserif","r",8)
 gc:drawString("Lua nSpaint - Par Loic Pujet",10,height()-12,"top")
end
Events.lua
Spoiler For Spoiler:
Code: [Select]
--EVENTS
function on.backspaceKey()
 if status=="requesting" then
  rqstr=string.sub(rqstr,1,string.len(rqstr)-1)
  refresh()
 end
end

function on.charIn(ch)
 ch=ch=="(" and " " or ch --avoid patterns
 if status=="drawing" then
  if string.find("NOS+-defphsclr",ch) then
   menuShortcut(ch)
  end
 elseif status=="requesting" and string.len(rqstr)<10 and string.find("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",ch) then
  rqstr=rqstr..ch
 end
 refresh()
end

function on.escapeKey()
 if status=="drawing" then
  tool=nil
 else
  status="drawing"
 end
 refresh()
end

function on.enterKey()
 if status=="drawing" and tool and imgTable then
  toolAction[tool]()
 elseif status=="selectingColor" then
  color=newColor
  status="drawing"
 elseif status=="requesting" then
  status="drawing"
  requestAction()
 elseif status=="error" then
  status="drawing"
 end
 refresh()
end

function on.arrowKey(ar)
 if status=="drawing" and imgTable then
  if tool then
   if ar=="up" and yPos>1 then yPos=yPos-1 end
   if ar=="down" and yPos<imgHeight then yPos=yPos+1 end
   if ar=="left" and xPos>1 then xPos=xPos-1 end
   if ar=="right" and xPos<imgWidth then xPos=xPos+1 end
  else
   if ar=="down" and (imgHeight-yScroll)*imgZoom>height()-45 then yScroll=yScroll+1 end
   if ar=="up" and yScroll>0 then yScroll=yScroll-1 end
   if ar=="right" and (imgWidth-xScroll)*imgZoom>width()-45 then xScroll=xScroll+1 end
   if ar=="left" and xScroll>0 then xScroll=xScroll-1 end
  end
 elseif status=="selectingColor" then
  if ar=="up" then
   selColor=selColor-1
  elseif ar=="down" then
   selColor=selColor+1
  elseif ar=="right" and newColor[selColor]<251 then
   newColor[selColor]=newColor[selColor]+5
  elseif ar=="left" and newColor[selColor]>4 then
   newColor[selColor]=newColor[selColor]-5
  end
  if selColor>3 then
   selColor=1
  elseif selColor<1 then
   selColor=3
  end
 end
 refresh()
end

function on.resize()
 xScroll=0
 yScroll=0
end
ImgTools.lua
Spoiler For Spoiler:
Code: [Select]
imgTools={}

function imgTools.getPixel(byte1,byte2)
 local str2
 str2=imgTools.addZeros(mathTools.base10to2(tonumber(byte2)),8)..imgTools.addZeros(mathTools.base10to2(tonumber(byte1)),8)
 return {tonumber(string.sub(str2,1,1)),mathTools.base2to10(string.sub(str2,2,6)),mathTools.base2to10(string.sub(str2,7,11)),mathTools.base2to10(string.sub(str2,12,16))}
end

function imgTools.getSize(img)
 imgWidth=mathTools.base2to10(mathTools.base10to2(tonumber(string.sub(img,10,12)..string.sub(img,7,9)..string.sub(img,4,6)..string.sub(img,1,3))))
 imgHeight=mathTools.base2to10(mathTools.base10to2(tonumber(string.sub(img,22,24)..string.sub(img,19,21)..string.sub(img,16,18)..string.sub(img,13,15))))
end

function imgTools.addZeros(str,strSize)
 return string.rep("0",strSize-string.len(str))..str
end

function imgTools.convertChars(img)
 local finished,img2,index
 index=1
 img2=""
 finished=nil
 while not finished do
  if string.sub(img,index,index)~=[[\]] then
   img2=img2..imgTools.addZeros(tostring(string.byte(string.sub(img,index,index))),3)
   index=index+1
  else
   img2=img2..string.sub(img,index+1,index+3)
   index=index+4
  end
  if index>string.len(img) then
   finished=1
  end
 end
 return img2
end

function imgTools.generateHeader()
 local binaryHeader,header
 binaryHeader={}
 binaryHeader[1]=imgTools.addZeros(mathTools.base10to2(imgWidth),32)
 binaryHeader[2]=imgTools.addZeros(mathTools.base10to2(imgHeight),32)
 binaryHeader[3]=imgTools.addZeros(mathTools.base10to2(imgWidth*2),32)
 header={"","",""}
 for i=1,3 do
  for j=3,0,-1 do
   header[i]=header[i]..imgTools.addZeros(tostring(mathTools.base2to10(string.sub(binaryHeader[i],8*j+1,8*(j+1)))),3)
  end
 end
 return header[1]..header[2].."000000000000"..header[3].."016000001000"
end

function imgTools.convertPixel(pixel)
 local str
 str=tostring(pixel[1])..imgTools.addZeros(mathTools.base10to2(pixel[2]),5)..imgTools.addZeros(mathTools.base10to2(pixel[3]),5)..imgTools.addZeros(mathTools.base10to2(pixel[4]),5)
 return imgTools.addZeros(tostring(mathTools.base2to10(string.sub(str,9,16))),3)..imgTools.addZeros(tostring(mathTools.base2to10(string.sub(str,1,8))),3)
end

function imgTools.addSlashes(str)
 local finished,str2,index
 finished=nil
 str2=[[\]]..str
 index=1
 while not finished do
  index=index+4
  if index>string.len(str2) then
   finished=1
  else
   str2=string.sub(str2,1,index-1)..[[\]]..string.sub(str2,index)
  end
 end
 return str2
end

function imgTools.img2table(str)
 local index
 str2=imgTools.convertChars(str)
 imgTable={}
 imgTools.getSize(str2)
 for i=1,imgWidth do
  imgTable[i]={}
  for j=1,imgHeight do
   index=(i-1)*6+61+(j-1)*6*imgWidth
   imgTable[i][j]=imgTools.getPixel(string.sub(str2,index,index+2),string.sub(str2,index+3,index+5))
  end
 end
end

function imgTools.drawTable(gc,x,y)
 gc:setColorRGB(0,0,0)
 gc:setPen("thin","dashed")
 gc:drawRect(x-1,y-1,imgWidth*imgZoom+1,imgHeight*imgZoom+1)
 gc:setPen("thin","smooth")
 for i=1,imgWidth do
  for j=1,imgHeight do
   if imgTable[i][j][1]==1 then
    gc:setColorRGB(math.floor(imgTable[i][j][2]*255/31),math.floor(imgTable[i][j][3]*255/31),math.floor(imgTable[i][j][4]*255/31))
    gc:fillRect((i-1)*imgZoom+x,(j-1)*imgZoom+y,imgZoom,imgZoom)
   else
    gc:setColorRGB(175,175,175)
    for k=0,imgZoom-1 do
     gc:fillRect((i-1)*imgZoom+x+k,(j-1)*imgZoom+y+k,1,1)
    end
   end
  end
 end
end

function imgTools.table2img()
 local imgStr
 imgStr=imgTools.generateHeader()
 for i=1,imgHeight do
  for j=1,imgWidth do
   imgStr=imgStr..imgTools.convertPixel(imgTable[j][i])
  end
 end
 return imgTools.addSlashes(imgStr)
end


Filters.lua
Spoiler For Spoiler:
Code: [Select]

function applyFilter(filterID)
 if imgTable then
  if filterID=="i" then
   filters.invertColors()
  elseif filterID=="r" then
   filters.randomImg()
  end
  changedMark="*"
  refresh()
 end
end




filters={}

function filters.invertColors()
 for i=1,imgWidth do
  for j=1,imgHeight do
   local previous=copyTable(imgTable[i][j])
   imgTable[i][j]={previous[1],31-previous[2],31-previous[3],31-previous[4]}
  end
 end
end

function filters.randomImg()
 for i=1,imgWidth do
  for j=1,imgHeight do
   local previous=copyTable(imgTable[i][j])
   imgTable[i][j]={1,math.random(0,31),math.random(0,31),math.random(0,31)}
  end
 end
end


As usual, the TNS file is attached with a screenie (I can't use TI Nspire CAS Software anymore, so it's grayscale)
Title: Re: [Lua] Image Editor
Post by: Chockosta on October 30, 2011, 01:11:56 pm
Sorry, I have to double-post, because all my code won't fit in my previous post.

Here is the missing file : Functions.lua
Spoiler For Spoiler:
Code: [Select]
--MATHTOOLS
mathTools={}

function mathTools.base10to2(n)
 local str
 str=""
 if n~=0 then
  while n~=1 do
   str=str..tostring(n%2)
   n=math.floor(n/2)
  end
  str=str..tostring(n%2)
  return string.reverse(str)
 else
  return "0"
 end
end

function mathTools.base2to10(n)
 local num = 0
 local ex = string.len(n) - 1
 local l = 0
 l = ex + 1
 for i = 1, l do
  b = string.sub(n, i, i)
  if b == "1" then
   num = num + 2^ex
  end
  ex = ex - 1
 end
 return num
end

function mathTools.int2Hex(int)
 if int<10 then
  return tostring(int)
 else
  if int==10 then return "A"
  elseif int==11 then return "B"
  elseif int==12 then return "C"
  elseif int==13 then return "D"
  elseif int==14 then return "E"
  elseif int==15 then return "F"
  end
 end
end



--FILE

file={}

function file.save()
 if rqstr=="" then
  status="error"
  errtype="Please type a name"
 elseif string.find("0123456789",string.sub(rqstr,1,1)) then
  status="error"
  errtype="Invalid name"
 else
  imgString=imgTools.table2img()
  var.store(rqstr,imgString)
  imgName=rqstr
  changedMark=""
 end
end

function file.load()
 local test
 test=var.recall(rqstr)
 if not test then
  status="error"
  errtype="File does not exist"
 elseif type(test)~="string" then
  status="error"
  errtype="Invalid file"
 else
  imgZoom=1
  xPos=1
  yPos=1
  xScroll=0
  yScroll=0
  tool=nil
  changedMark=""
  imgString=test
  imgTools.img2table(imgString)
  imgName=rqstr
 end
end

function file.new()
 imgWidth=tempVarWidth
 imgHeight=tonumber(rqstr)
 imgZoom=1
 xPos=1
 yPos=1
 xScroll=0
 yScroll=0
 tool=nil
 changedMark=""
 imgName="unsaved"
 imgTable={}
 for i=1,imgWidth do
  imgTable[i]={}
  for j=1,imgHeight do
   imgTable[i][j]={0,0,0,0}
  end
 end
end





--MISCELLANEOUS

function width()
 return platform.window:width()
end

function height()
 return platform.window:height()
end

function refresh()
 platform.window:invalidate()
end

function copyTable(t)
  local t2 = {}
  for k,v in pairs(t) do
    t2[k] = v
  end
  return t2
end

function samePixels(px1,px2)
 if (px1[1]==px2[1] and px1[2]==px2[2] and px1[3]==px2[3] and px1[4]==px2[4]) or (px1[1]==0 and px2[1]==0) then
  return 1
 else
  return nil
 end
end

function fillPixel(x,y)
 local previousPixel,xTest,yTest
 previousPixel=copyTable(imgTable[x][y])
 if not samePixels(previousPixel,{1,math.floor(color[1]*31/255),math.floor(color[2]*31/255),math.floor(color[3]*31/255)}) then
  changedMark="*"
  imgTable[x][y]={1,math.floor(color[1]*31/255),math.floor(color[2]*31/255),math.floor(color[3]*31/255)}
  for i=1,4 do
   xTest=math.floor(i/2)-1+x
   yTest=(i==3 and 1 or 0)-(i==2 and 1 or 0)+y
   if xTest>0 and xTest<imgWidth+1 and yTest>0 and yTest<imgHeight+1 then
    if samePixels(previousPixel,imgTable[xTest][yTest]) then
     fillPixel(xTest,yTest)
    end
   end
  end
 end
end

function setPixel(x,y)
 if x>=1 and x<=imgWidth and y>=1 and y<=imgHeight then
  imgTable[x][y]={1,math.floor(color[1]*31/255),math.floor(color[2]*31/255),math.floor(color[3]*31/255)}
 end
end

function drawCircle(x1,y1,x2,y2)
 local rayon=math.floor(math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))+0.01)
 local x,y,m
 x=0
 y=rayon
 m=5-4*rayon
 while x<=y do
  setPixel(x+x1,y+y1)
  setPixel(y+x1,x+y1)
  setPixel(-x+x1,y+y1)
  setPixel(-y+x1,x+y1)
  setPixel(x+x1,-y+y1)
  setPixel(y+x1,-x+y1)
  setPixel(-x+x1,-y+y1)
  setPixel(-y+x1,-x+y1)
  if m>0 then
   y=y-1
   m=m-8*y
  end
  x=x+1
  m=m+8*x+4
 end
 changedMark="*"
end

function round(nb)
 if nb>math.floor(nb)+0.5 then
  return math.floor(nb)+1
 else
  return math.floor(nb)
 end
end

function drawLine(x1,y1,x2,y2)
 local reversed=nil
 if x1>x2 then
  x1,x2=x2,x1
  reversed=not reversed
 end
 if y1>y2 then
  y1,y2=y2,y1
  reversed=not reversed
 end
 local size=x2-x1>y2-y1 and x2-x1 or y2-y1
 for i=0,size do
  if reversed then
   setPixel(x1+(x2-x1)-round((i/size)*(x2-x1)),y1+round((i/size)*(y2-y1)))
  else
   setPixel(x1+round((i/size)*(x2-x1)),y1+round((i/size)*(y2-y1)))
  end
 end
 changedMark="*"
end

function drawRect(x1,y1,x2,y2)
 if x1>x2 then
  x1,x2=x2,x1
 end
 if y1>y2 then
  y1,y2=y2,y1
 end
 for i=x1,x2 do
  setPixel(i,y1)
  setPixel(i,y2)
 end
 for i=y1,y2 do
  setPixel(x1,i)
  setPixel(x2,i)
 end
 changedMark="*"
end

function fillRect(x1,y1,x2,y2)
 if x1>x2 then
  x1,x2=x2,x1
 end
 if y1>y2 then
  y1,y2=y2,y1
 end
 for i=x1,x2 do
  for j=y1,y2 do
   setPixel(i,j)
  end
 end
 changedMark="*"
end

function fillCircle(x1,y1,x2,y2)
 local rayon=math.floor(math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))+0.5)
 local startX,endX,startY,endY
 startX=x1-rayon
 endX=x1+rayon
 startY=y1-rayon
 endY=y1+rayon
 for i=startX,endX do
  for j=startY,endY do
   if (x1-i)*(x1-i)+(y1-j)*(y1-j)-(rayon+1)/2<=rayon*rayon then
    setPixel(i,j)
   end
  end
 end
 changedMark="*"
end

function loadHexColor()
 local isHex,tmptable
 isHex=1
 tmptable={}
 if string.len(rqstr)==6 then
  for i=1,6,1 do
   currentch=string.sub(rqstr,i,i)
   tmptable[i]=tonumber(currentch,16)
   if not tmptable[i] then
    isHex=nil
   end
  end
 else isHex=nil
 end
 if isHex then
  color={tmptable[1]*16+tmptable[2],tmptable[3]*16+tmptable[4],tmptable[5]*16+tmptable[6]}
 else
  status="error"
  errtype="Invalid hexadecimal"
 end
end

function eraseImg()
 if imgTable then
  for i=1,imgWidth do
   for j=1,imgHeight do
    imgTable[i][j][1]=0
   end
  end
  changedMark="*"
  refresh()
 end
end

function flipH()
 if imgTable then
  local newImg={}
  for i=1,imgWidth do
   newImg[i]={}
   for j=1,imgHeight do
    newImg[i][j]=copyTable(imgTable[imgWidth-i+1][j])
   end
  end
  imgTable=newImg
  changedMark="*"
  refresh()
 end
end

function flipV()
 if imgTable then
  local newImg={}
  for i=1,imgWidth do
   newImg[i]={}
   for j=1,imgHeight do
    newImg[i][j]=copyTable(imgTable[i][imgHeight-j+1])
   end
  end
  imgTable=newImg
  changedMark="*"
  refresh()
 end
end

function rotateImg(mode)
 if imgTable then
  xScroll,yScroll=0,0
  xPos,yPos=1,1
  local newImg={}
  for i=1,imgHeight do
   newImg[i]={}
   for j=1,imgWidth do
    if mode=="c" then
     newImg[i][j]=copyTable(imgTable[j][imgHeight-i+1])
    else
     newImg[i][j]=copyTable(imgTable[imgWidth-j+1][i])
    end
   end
  end
  imgWidth,imgHeight=imgHeight,imgWidth
  imgTable=newImg
  changedMark="*"
  refresh()
 end
end


Title: Re: [Lua] Image Editor
Post by: Adriweb on October 30, 2011, 02:19:13 pm
Congratulations, very cool :D
Title: Re: [Lua] Image Editor
Post by: AzNg0d1030 on October 30, 2011, 10:26:56 pm
Hehe even my avatar is advertising nSpaint... :PPPP  :hyper:
Title: Re: [Lua] Image Editor
Post by: Chockosta on October 31, 2011, 06:15:21 am
:)

Did you draw it entirely or did you just upload it ?
Title: Re: [Lua] Image Editor
Post by: Yeong on October 31, 2011, 07:19:43 am
can I have a link for the manual? :D
Title: Re: [Lua] Image Editor
Post by: Chockosta on October 31, 2011, 07:21:45 am
I don't have written any readme
/me runs

But everything should be listed in the menu
Title: Re: [Lua] Image Editor
Post by: Yeong on October 31, 2011, 07:24:41 am
Oh yeah. I'm keep forgetting to try menu button XP
thanks XD
Title: Re: [Lua] Image Editor
Post by: DJ Omnimaga on December 25, 2011, 09:59:44 pm
I like the new features. I didn't try this yet but I should really do so, soon. I haven't read the thread yet but I am curious how the sprite saving/exporting (if any exporting) works? Is it possible to create sprites for use in other tns files? I don't recall the Nspire having any form of external file like on the 83+.
Title: Re: [Lua] Image Editor
Post by: Adriweb on December 26, 2011, 05:20:36 am
I like the new features. I didn't try this yet but I should really do so, soon. I haven't read the thread yet but I am curious how the sprite saving/exporting (if any exporting) works? Is it possible to create sprites for use in other tns files? I don't recall the Nspire having any form of external file like on the 83+.

Actually when you copy/paste things, it stays in memory even when you close the current document.
So you can put something from a doc to another that way.

But anyway, there is another way that consists into saving a var in a public document stored in the MyLib folder, because this one can be accessed "dynamically" whenever and from wherever you want, so this is good for sharing stuff between docs.
This is the technique we'll use in EEPro. (for loading user-made custom formula databases)
Title: Re: [Lua] Image Editor
Post by: DJ Omnimaga on December 27, 2011, 01:11:48 am
I see, but how do we retrieve it? Is there a function in Lua that does that or do you access memory directly?
Title: Re: [Lua] Image Editor
Post by: Adriweb on December 27, 2011, 06:42:19 am
I see, but how do we retrieve it? Is there a function in Lua that does that or do you access memory directly?
There are clipboard setter and getters, yes.
Same for math variables :)
Title: Re: [Lua] Image Editor
Post by: Chockosta on December 28, 2011, 02:19:32 pm
I am currently rewriting this project...
It should not take too much time, so expect some news soon...
Title: Re: [Lua] Image Editor
Post by: DJ Omnimaga on December 30, 2011, 06:06:41 pm
Good to hear. Good luck! :)
Title: Re: [Lua] Image Editor
Post by: Chockosta on December 31, 2011, 11:13:53 am
Some work on the GUI...
It is now possible to open a native-like window with 1 line :
Code: [Select]
gui.addWindow("Title","dialogBox","This text shows multi-line text functions :\nLorem ipsum dolor sit amet",{{"Button 1"},{"Button 2"},{"Another button"}})
See attachment for result.
Title: Re: [Lua] Image Editor
Post by: Adriweb on December 31, 2011, 12:29:20 pm
That's some impressive native-looking window.

Did you do it by yourself or took some routines from EEPro ? :) (No proble, if you did :) )
If you didn't, we could use some of your code for EEPro, then ?

(You'd be a contributor if you want, actually)


Edit :  Also, code ? :D
Title: Re: [Lua] Image Editor
Post by: DJ Omnimaga on December 31, 2011, 03:24:30 pm
Looks pretty nice indeed. :)
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on December 31, 2011, 05:21:32 pm
Wow, I'm also busy on a GUI api (for EEPro) that looks like native dialogs (some of my dialogs can just look the same as yours :P)
Maybe we can share ideas?
Title: Re: [Lua] Image Editor
Post by: Chockosta on January 01, 2012, 04:35:44 am
@Adriweb :
I didn't take any routine from EEPro. If I did, I would have mentioned it. By the way, I didn't know that the source code of EEPro was visible... Where could I see it ?
You sure can use my code, but for now there is almost nothing. (no event gestion, no custom layout...)
And it might not be easy since I don't use OOP.

@DJ_O :
Thanks !

@jimbauwens :
I would be honored to share ideas with you, but my little GUI engine is nothing compared to EEPro API. I will just add text boxes, and it will be enough for me...

If you want the code of this sample, here it is :
Code: [Select]
--GUI GESTION
gui={}
gui.windows={}
gui.dialogBox={}

function gui.errorMessage(errorText)
 gui.addWindow("Error","dialogBox",errorText,{{"OK"}})
end

function gui.addWindow(windowName,windowType,text,buttons)
 table.insert(gui.windows,{windowName,windowType,text,buttons})
end

function gui.closeWindow()
 table.remove(gui.windows)
end

function gui.nbWindows()
 return #gui.windows
end

function gui.current()
 return gui.windows[#gui.windows]
end

function gui.paint(gc)
 for i,e in pairs(gui.windows) do
  gui[e[2]].paint(gc,e)
 end
end

function gui.dialogBox.paint(gc,dialogBox)
 gc:setFont("sansserif","r",10)
 local sizeX=improvedStr.width(gc,dialogBox[3])+24
 local sizeY=improvedStr.height(gc,dialogBox[3])+17
 gui.paintWindowBG(gc,dialogBox[1],sizeX,sizeY)
 gui.paintTextArea(gc,dialogBox[3],sizeX,sizeY)
 gui.paintButtons(gc,dialogBox[4],sizeX,sizeY)
end

function gui.paintButtons(gc,buttons,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 local size,totalSize,pos={},-7,{}
 for i,e in pairs(buttons) do
  size[i]=gc:getStringWidth(e[1])+10
  totalSize=totalSize+size[i]+7
 end
 pos[1]=(width()-totalSize)/2
 for i=2,#buttons do
  pos[i]=pos[i-1]+size[i-1]+7
 end
 for i,e in pairs(buttons) do
  gc:setColorRGB(136,136,136)
  gc:fillRect(pos[i],y+sizeY+9,size[i],23)
  gc:fillRect(pos[i]+1,y+sizeY+8,size[i]-2,25)
  gc:fillRect(pos[i]+2,y+sizeY+7,size[i]-4,27)
  gc:setColorRGB(255,255,255)
  gc:fillRect(pos[i]+2,y+sizeY+9,size[i]-4,23)
  gc:setColorRGB(0,0,0)
  gc:drawString(e[1],pos[i]+5,y+sizeY+20,"middle")
 end
end

function gui.paintTextArea(gc,text,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 if isCX() then
  gc:setColorRGB(128,128,128)
 else
  gc:setColorRGB(255,255,255)
 end
 gc:drawRect(x+6,y+6,sizeX-13,sizeY-13)
 gc:setColorRGB(0,0,0)
 improvedStr.draw(gc,text,x+12,y+9)
end

function gui.paintWindowBG(gc,name,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 if isCX() then
  gc:setColorRGB(100,100,100)
 else
  gc:setColorRGB(200,200,200)
 end
 gc:fillRect(x-1,y-23,sizeX+4,sizeY+65)
 gc:fillRect(x,y-22,sizeX+4,sizeY+65)
 gc:fillRect(x+1,y-21,sizeX+4,sizeY+65)
 if isCX() then
  gc:setColorRGB(128,128,128)
 else
  gc:setColorRGB(0,0,0)
 end
 gc:fillRect(x-2,y-24,sizeX+4,sizeY+65)
 if isCX() then
  for i=1,22 do
   gc:setColorRGB(32+i*3,32+i*3,32+i*3)
   gc:fillRect(x,y+i-23,sizeX,1)
  end
 else
  gc:setColorRGB(0,0,0)
  gc:fillRect(x,y-22,sizeX,22)
 end
 gc:setColorRGB(255,255,255)
 gc:setFont("sansserif","r",10)
 gc:drawString(name,x+2,y-9,"baseline")
 gc:setColorRGB(224,224,224)
 gc:fillRect(x,y,sizeX,sizeY+39)
 gc:setColorRGB(128,128,128)
 gc:fillRect(x+6,y+sizeY,sizeX-12,2)
end




--MULTIPLE LINE STRING GESTION
improvedStr={}

function improvedStr.draw(gc,str,x,y)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 for i,e in pairs(table1) do
  gc:drawString(e,x,y+(i-1)*gc:getStringHeight("a"),"top")
 end
end

function improvedStr.width(gc,str)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 local table2={}
 for i,e in pairs(table1) do
  table2[i]=gc:getStringWidth(e)
 end
 table.sort(table2)
 return table2[#table2]
end

function improvedStr.height(gc,str)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 return gc:getStringHeight("a")*#table1
end

function improvedStr.cut(str)
 local table1,finished={},false
 local posStart,posEnd,last=1,0,1
 while not finished do
  posStart,posEnd=string.find(str,"\n",posEnd+1)
  if posStart then
   table.insert(table1,string.sub(str,last,posStart-1))
   last=posEnd+1
  else
   table.insert(table1,string.sub(str,last))
   finished=true
  end
 end
 return unpack(table1)
end

-- END OF GUI
 
function width() return platform.window:width() end
function height() return platform.window:height() end
function isCX() return platform.isColorDisplay() end
 
gui.addWindow("Title","dialogBox","This text shows multi-line text functions :\nLorem ipsum dolor sit amet",{{"Button 1"},{"Button 2"},{"Another button"}})

function on.paint(gc)
 gui.paint(gc)
end
Title: Re: [Lua] Image Editor
Post by: Adriweb on January 01, 2012, 04:49:02 am
Really nice, thanks ;)

I'll let Jim Bauwens decide how these ideas are shared etc.

Maybe we should all (all the community) share our code and put it somewhere on GitHub in a seperate project ("nGUI ?"), in order to have a common GUI project library.
With everyone's code and ideas, we sure would have the best-looking library :)


Edit : I tested it and it works great : Indeed, it's purely graphical so no interactinos or whatever, but still, the graphical part and the awesome-native-look is a good point.
Jim's way in EEPro is actually more complex since everything in the dialog box is "modular" and can act with the keyboard/mouse since the list, the text inputs etc. are all widgets added to a main widget (the dialog box)
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on January 01, 2012, 06:45:41 am
What I will try to do is to make a similar dialog system. Right now I have to append all widgets to the dialog manually. As Adriweb suggested a couple of day's ago, I really should make (informative) dialog boxes as easy as yours :)

I didn't look yet at your code (I'm on my phone now), but I will do soon :)
Title: Re: [Lua] Image Editor
Post by: Chockosta on January 06, 2012, 02:07:03 pm
Some progress...
Now buttons work, and there is a draft of custom window layouts.

If you're interested, here is the code of the new sample :
Code: [Select]
--[[

window : {wtype,name,buttons,layout,size}
   --> wtype : "dialogBox","custom"
   --> size : {sizeX,sizeY} (only for custom)

buttons : {{"name",function1},{"name",function2},...}

layout : {{"type",...}}
   --> type : "label","textBox","colorSlider","list"

label : {text,x,y}

textBox : {text,x,y,sizeX,cursor}

colorSlider : {color,value,x,y}
   --> color : "red","green","blue"

list : {elements,scroll,x,y,sizeX,sizeY}

]]


--GUI GESTION
gui={}
gui.windows={}
gui.dialogBox={}
gui.custom={}
gui.resized=false

function gui.errorMessage(errorText)
 gui.addWindow("dialogBox","Error",{{"OK",function() gui.closeWindow() refresh() end}},errorText)
end

function gui.addWindow(windowType,windowName,windowButtons,windowLayout,windowSize)
 table.insert(gui.windows,{wtype=windowType,name=windowName,buttons=windowButtons,layout=windowLayout,size=windowSize})
 gui.focus=-1
end

function gui.closeWindow()
 table.remove(gui.windows)
 gui.focus=-1
end

function gui.nbWindows()
 return #gui.windows
end

function gui.current()
 return gui.windows[#gui.windows]
end

function gui.paint(gc)
 for i,e in pairs(gui.windows) do
  gui[e.wtype].paint(gc,e,i)
 end
 gui.resized=false
end

function gui.resize()
 gui.resized=true
end




--GUI DRAWING

function gui.dialogBox.paint(gc,dialogBox,windowID)
 local sizeX,sizeY
 if not dialogBox.size then
  gc:setFont("sansserif","r",10)
  sizeX=improvedStr.width(gc,dialogBox.layout)+24
  sizeY=improvedStr.height(gc,dialogBox.layout)+17
  gui.windows[windowID].size={sizeX,sizeY}
 else
  sizeX,sizeY=unpack(dialogBox.size)
 end
 gui.paintWindowBG(gc,dialogBox.name,sizeX,sizeY)
 gui.paintTextArea(gc,dialogBox.layout,sizeX,sizeY)
 gui.paintButtons(gc,dialogBox.buttons,sizeX,sizeY,windowID)
 if windowID==#gui.windows then
  gui.paintFocus(gc,gui.focus,dialogBox.buttons,dialogBox.layout,sizeX,sizeY)
 end
end

function gui.custom.paint(gc,window,windowID)
 gui.paintWindowBG(gc,window.name,window.size[1],window.size[2])
 gui.paintLayout(gc,window.layout,window.size[1],window.size[2],windowID)
 gui.paintButtons(gc,window.buttons,window.size[1],window.size[2],windowID)
 if windowID==#gui.windows then
  gui.paintFocus(gc,gui.focus,window.buttons,window.layout,window.size[1],window.size[2])
 end
end





function gui.paintLayout(gc,layout,sizeX,sizeY,windowID)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 for i,e in pairs(layout) do
  if e[1]=="textBox" then
   gui.paintTextBox(gc,e,x,y)
  elseif e[1]=="label" then
   gc:setFont("sansserif","r",10)
   gc:setColorRGB(0,0,0)
   gc:drawString(e.text,x+e.x,y+e.y,"top")
  elseif e[1]=="colorSlider" then
   gui.paintColorSlider(gc,e,x,y)
  end
 end
end

function gui.paintTextBox(gc,textBox,x,y)
 gc:setColorRGB(255,255,255)
 gc:fillRect(x+textBox.x,y+textBox.y,textBox.sizeX,22)
 gc:setColorRGB(0,0,0)
 gc:drawRect(x+textBox.x,y+textBox.y,textBox.sizeX,22)
 gc:drawString(string.sub(textBox.text,1,textBox.cursor-1).."|"..string.sub(textBox.text,textBox.cursor),x+textBox.x+3,y+textBox.y,"top")
end

function gui.paintColorSlider(gc,slider,x,y)
 gc:setColorRGB(0,0,0)
 gc:fillRect(x+slider.x,y+slider.y,68,14)
 for i=0,63 do
  gc:setColorRGB(slider.color=="red" and i*4 or color[1],slider.color=="green" and i*4 or color[2],slider.color=="blue" and i*4 or color[3])
  gc:fillRect(x+slider.x+i+2,y+2+slider.y,1,10)
 end
 gc:setColorRGB(0,0,0)
 gc:fillRect(x+slider.x+slider.value/4+1,y+slider.y,1,12)
 gc:fillRect(x+slider.x+slider.value/4+3,y+slider.y,1,12)
end

function gui.paintButtons(gc,buttons,sizeX,sizeY,windowID)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 if (not buttons[1].size) or gui.resized then
  local totalSize,size,pos=-7,{},{}
  for i,e in pairs(buttons) do
   size[i]=gc:getStringWidth(e[1])+10
   totalSize=totalSize+size[i]+7
  end
  pos[1]=(width()-totalSize)/2
  for i=2,#buttons do
   pos[i]=pos[i-1]+size[i-1]+7
  end
  for i,e in pairs(buttons) do
   gui.windows[windowID].buttons[i].size=size[i]
   gui.windows[windowID].buttons[i].pos=pos[i]
  end
  buttons=gui.windows[windowID].buttons
 end
 for i,e in pairs(buttons) do
  gc:setColorRGB(136,136,136)
  gc:fillRect(e.pos,y+sizeY+9,e.size,23)
  gc:fillRect(e.pos+1,y+sizeY+8,e.size-2,25)
  gc:fillRect(e.pos+2,y+sizeY+7,e.size-4,27)
  gc:setColorRGB(255,255,255)
  gc:fillRect(e.pos+2,y+sizeY+9,e.size-4,23)
  gc:setColorRGB(0,0,0)
  gc:drawString(e[1],e.pos+5,y+sizeY+20,"middle")
 end
end

function gui.paintTextArea(gc,text,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 if isCX() then
  gc:setColorRGB(128,128,128)
 else
  gc:setColorRGB(255,255,255)
 end
 gc:drawRect(x+6,y+6,sizeX-13,sizeY-13)
 gc:setColorRGB(0,0,0)
 improvedStr.draw(gc,text,x+12,y+9)
end

function gui.paintWindowBG(gc,name,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 if isCX() then
  gc:setColorRGB(100,100,100)
 else
  gc:setColorRGB(200,200,200)
 end
 gc:fillRect(x-1,y-23,sizeX+4,sizeY+65)
 gc:fillRect(x,y-22,sizeX+4,sizeY+65)
 gc:fillRect(x+1,y-21,sizeX+4,sizeY+65)
 if isCX() then
  gc:setColorRGB(128,128,128)
 else
  gc:setColorRGB(0,0,0)
 end
 gc:fillRect(x-2,y-24,sizeX+4,sizeY+65)
 if isCX() then
  for i=1,22 do
   gc:setColorRGB(32+i*3,32+i*3,32+i*3)
   gc:fillRect(x,y+i-23,sizeX,1)
  end
 else
  gc:setColorRGB(0,0,0)
  gc:fillRect(x,y-22,sizeX,22)
 end
 gc:setColorRGB(255,255,255)
 gc:setFont("sansserif","r",10)
 gc:drawString(name,x+2,y-9,"baseline")
 gc:setColorRGB(224,224,224)
 gc:fillRect(x,y,sizeX,sizeY+39)
 gc:setColorRGB(128,128,128)
 gc:fillRect(x+6,y+sizeY,sizeX-12,2)
end

function gui.paintFocus(gc,focus,buttons,layout,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 if focus>0 then
  if type(layout)=="table" then

  end
 elseif focus<0 then
  local button=buttons[-focus]
  if isCX() then
   gc:setColorRGB(50,150,190)
  else
   gc:setColorRGB(0,0,0)
  end
  gc:drawRect(button.pos-3,y+sizeY+4,button.size+5,32)
  gc:drawRect(button.pos-2,y+sizeY+5,button.size+3,30)
 end
end




--GUI EVENTS
function gui.mouseDown(xPos,yPos)
 if gui.nbWindows()>=1 then
  local window=gui.current()
  if window.size then
   local sizeX,sizeY=unpack(window.size)
   local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
   if xPos>x and xPos<x+sizeX and yPos>y then
    if yPos<y+sizeY then
     gui.setFocus(xPos,yPos,window)
    elseif yPos<y+sizeY+39 then
     gui.buttonDown(xPos,yPos,window.buttons)
    end
   end
  end
 end
end

function gui.buttonDown(x,y,buttons)
 for i,e in pairs(buttons) do
  if x>e.pos and x<e.pos+e.size then
   gui.focus=-i
   e[2]()
  end
 end
end

function gui.setFocus(x,y,window)
 
end


--MULTIPLE LINE STRING GESTION
improvedStr={}

function improvedStr.draw(gc,str,x,y)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 for i,e in pairs(table1) do
  gc:drawString(e,x,y+(i-1)*gc:getStringHeight("a"),"top")
 end
end

function improvedStr.width(gc,str)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 local table2={}
 for i,e in pairs(table1) do
  table2[i]=gc:getStringWidth(e)
 end
 table.sort(table2)
 return table2[#table2]
end

function improvedStr.height(gc,str)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 return gc:getStringHeight("a")*#table1
end

function improvedStr.cut(str)
 local table1,finished={},false
 local posStart,posEnd,last=1,0,1
 while not finished do
  posStart,posEnd=string.find(str,"\n",posEnd+1)
  if posStart then
   table.insert(table1,string.sub(str,last,posStart-1))
   last=posEnd+1
  else
   table.insert(table1,string.sub(str,last))
   finished=true
  end
 end
 return unpack(table1)
end
Title: Re: [Lua] Image Editor
Post by: Nick on January 06, 2012, 02:33:58 pm
wow, amazing.. those look really native :o congratz
Title: Re: [Lua] Image Editor
Post by: AzNg0d1030 on January 06, 2012, 08:25:27 pm
Dang I can't wait to update my 0.6 to this one you're working on.  Seems amazing!  All these little additions are making this one great app
Title: Re: [Lua] Image Editor
Post by: Chockosta on January 20, 2012, 04:37:49 pm
I finished the GUI engine, it now handles mouse events and everything. (almost)
So now I start to write new functions !

If you are interested, here is the source code of a demo :
Code: [Select]
--[[

window : {wtype,name,buttons,layout,size}
   --> wtype : "dialogBox","custom"
   --> size : {sizeX,sizeY} (only for custom)

buttons : {{"name",function1},{"name",function2},...}

layout : {{"type",...}}
   --> type : "label","textBox","colorSlider","list"

label : {text,x,y}

textBox : {text,x,y,sizeX,cursor}

colorSlider : {color,value,x,y}
   --> color : "red","green","blue"

list : {elements,scroll,x,y,sizeX,sizeY,selected}

]]


--GUI GESTION
gui={}
gui.windows={}
gui.dialogBox={}
gui.custom={}
gui.textBox={}
gui.colorSlider={}
gui.list={}
gui.resized=false
gui.img={}
gui.img.upButton=image.new("\011\000\000\000\010\000\000\000\000\000\000\000\022\000\000\000\016\000\001\0001\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\198\255\255\255\255\255\255\255\255\156\243\255\255\255\255\255\255\255\2551\1981\198\255\255\255\255\255\255\214\218\000\128\214\218\255\255\255\255\255\2551\1981\198\255\255\255\255\247\222B\136\000\128B\136\247\222\255\255\255\2551\1981\198\255\255\247\222B\136!\132\000\128!\132B\136\247\222\255\2551\1981\198\247\222B\136!\132B\136R\202B\136!\132B\136\247\2221\1981\198\132\144B\136B\136\247\222\255\255\247\222B\136B\136\132\1441\1981\198\156\243\132\144\247\222\255\255\255\255\255\255\247\222\132\144\189\2471\1981\198\255\255\222\251\255\255\255\255\255\255\255\255\255\255\222\251\255\2551\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\198")
gui.img.downButton=image.new("\011\000\000\000\010\000\000\000\000\000\000\000\022\000\000\000\016\000\001\0001\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\198\255\255\222\251\255\255\255\255\255\255\255\255\255\255\222\251\255\2551\1981\198\156\243\132\144\247\222\255\255\255\255\255\255\247\222\132\144\189\2471\1981\198\132\144B\136B\136\247\222\255\255\247\222B\136B\136\132\1441\1981\198\247\222B\136!\132B\136R\202B\136!\132B\136\247\2221\1981\198\255\255\247\222B\136!\132\000\128!\132B\136\247\222\255\2551\1981\198\255\255\255\255\247\222B\136\000\128B\136\247\222\255\255\255\2551\1981\198\255\255\255\255\255\255\214\218\000\128\214\218\255\255\255\255\255\2551\1981\198\255\255\255\255\255\255\255\255\156\243\255\255\255\255\255\255\255\2551\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\198")


--GUI UTILS


function gui.errorMessage(errorText)
 gui.addWindow("dialogBox","Error",{{"OK",function() gui.closeWindow() refresh() end}},errorText)
end

function gui.addWindow(windowType,windowName,windowButtons,windowLayout,windowSize)
 table.insert(gui.windows,{wtype=windowType,name=windowName,buttons=windowButtons,layout=windowLayout,size=windowSize})
 gui.focus=-1
 refresh()
end

function gui.closeWindow()
 table.remove(gui.windows)
 gui.focus=-1
 refresh()
end

function gui.nbWindows()
 return #gui.windows
end

function gui.current()
 return gui.windows[#gui.windows]
end

function gui.refreshCurrent()
 local current=gui.current()
 local sizeX,sizeY=unpack(current.size)
 local xPos,yPos=(width()-sizeX)/2,(height()-sizeY-15)/2
 refresh(xPos,yPos,sizeX,sizeY+39)
end



--GUI EVENTS
function gui.mouseDown(xPos,yPos)
 if gui.nbWindows()>=1 then
  local window=gui.current()
  if window.size then
   local sizeX,sizeY=unpack(window.size)
   local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
   if xPos>x and xPos<x+sizeX and yPos>y then
    if yPos<y+sizeY and gui.current().wtype=="custom" then
     gui.setFocus(xPos-x,yPos-y,window)
    elseif yPos>y+sizeY and yPos<y+sizeY+39 then
     gui.buttonDown(xPos,yPos,window.buttons)
    end
   end
  end
 end
end

function gui.paint(gc)
 for i,e in pairs(gui.windows) do
  gui[e.wtype].paint(gc,e,i)
 end
 gui.resized=false
end

function gui.resize()
 gui.resized=true
end

function gui.tabKey()
 if gui.nbWindows()>0 then
  gui.moveFocus(1)
  gui.refreshCurrent()
 end
end

function gui.backtabKey()
 if gui.nbWindows()>0 then
  gui.moveFocus(-1)
  gui.refreshCurrent()
 end
end

function gui.arrowKey(arrow)
 if gui.nbWindows()>0 then
  if gui.focus<0 then
   if arrow=="left" then
    gui.moveFocus(1)
    gui.refreshCurrent()
   elseif arrow=="right" then
    gui.moveFocus(-1)
    gui.refreshCurrent()
   end
  elseif gui.focus>0 then
   local currentElem=gui.current().layout[gui.focus]
   if gui[currentElem[1]].arrowKey then
    gui[currentElem[1]].arrowKey(arrow,currentElem)
    gui.refreshCurrent()
   end
  end
 end
end

function gui.enterKey()
 if gui.nbWindows()>0 then
  if gui.focus<0 then
   gui.current().buttons[-gui.focus][2]()
  end
 end
end

function gui.charIn(char)
 if gui.nbWindows()>0 then
  if gui.focus>0 then
   local currentElem=gui.current().layout[gui.focus]
   if gui[currentElem[1]].charIn then
    gui[currentElem[1]].charIn(char,currentElem)
    gui.refreshCurrent()
   end
  end
 end
end

function gui.backspaceKey()
 if gui.nbWindows()>0 then
  if gui.focus>0 then
   local currentElem=gui.current().layout[gui.focus]
   if gui[currentElem[1]].backspaceKey then
    gui[currentElem[1]].backspaceKey(currentElem)
    gui.refreshCurrent()
   end
  end
 end
end

function gui.escapeKey()
 if gui.nbWindows()>0 then
  gui.closeWindow()
 end
end



--GUI LAYOUT ELEMENTS EVENTS

function gui.textBox.charIn(char,textBox)
 if string.len(char)==1 then
  textBox.prev={textBox.text,textBox.cursor}
  textBox.text=string.usub(textBox.text,1,textBox.cursor)..char..string.usub(textBox.text,textBox.cursor+1)
  textBox.cursor=textBox.cursor+1
 end
end

function gui.textBox.arrowKey(arrow,textBox)
 if arrow=="right" and textBox.cursor<string.len(textBox.text) then
  textBox.cursor=textBox.cursor+1
 elseif arrow=="left" and textBox.cursor>0 then
  textBox.cursor=textBox.cursor-1
 end
end

function gui.textBox.mouseDown(textBox,x)
 textBox.setCursor=x-2
end

function gui.textBox.backspaceKey(textBox)
 if string.len(textBox.text)>0 then
  textBox.text=string.usub(textBox.text,1,textBox.cursor-1)..string.usub(textBox.text,textBox.cursor+1)
  textBox.cursor=textBox.cursor-1
 end
end

function gui.colorSlider.arrowKey(arrow,slider)
 if arrow=="right" then
  slider.value=slider.value<250 and slider.value+5 or 255
 elseif arrow=="left" then
  slider.value=slider.value>5 and slider.value-5 or 0
 end
end

function gui.colorSlider.mouseDown(slider,x)
 x=(x-2)*4
 x=x>0 and x or 0
 x=x<255 and x or 255
 slider.value=x
end

function gui.list.arrowKey(arrow,list)
 if arrow=="up" and list.selected>1 then
  list.selected=list.selected-1
 elseif arrow=="down" and list.selected<#list.elements then
  list.selected=list.selected+1
 end
end

function gui.list.mouseDown(list,x,y)
 if x>list.sizeX-17 then
  if y>list.sizeY/2 and list.selected<#list.elements then
   list.selected=list.selected+1
  elseif y<list.sizeY/2 and list.selected>1 then
   list.selected=list.selected-1
  end
 else
  list.setSelection=y
 end
end


--GUI MISC FUNCTIONS

function gui.moveFocus(nb)
 local currentWindow=gui.current()
 local test=false
 local originalFocus=gui.focus
 nb=gui.focus<0 and -nb or nb
 gui.focus=gui.focus+nb
 if #currentWindow.buttons==0 then
  gui.focus=-1
  test=true
 end
 while not test do
  if gui.focus<0 then
   if -gui.focus<=#currentWindow.buttons then
    test=true
   else
    gui.focus=1
    nb=1
   end
  elseif gui.focus==0 then
   if originalFocus<0 then
    if currentWindow.wtype=="dialogBox" then
     gui.focus=-#currentWindow.buttons
     test=true
    elseif #currentWindow.layout==0 then
     gui.focus=-#currentWindow.buttons
     test=true
    else
     gui.focus=#currentWindow.layout
    end
   else
    gui.focus=nb<0 and -1 or 1
   end
  else
   if currentWindow.wtype=="dialogBox" then
    test=true
    gui.focus=-1
   elseif currentWindow.wtype=="custom" then
    if gui.focus<=#currentWindow.layout then
     if currentWindow.layout[gui.focus][1]=="label" then
      gui.focus=gui.focus+(nb<0 and -1 or 1)
     else
      test=true
     end
    else
     test=true
     gui.focus=-1
    end
   end
  end
 end
end

function gui.buttonDown(x,y,buttons)
 for i,e in pairs(buttons) do
  if x>e.pos and x<e.pos+e.size then
   gui.focus=-i
   e[2]()
  end
 end
end

function gui.setFocus(x,y,window)
 for i,e in pairs(window.layout) do
  if e[1]=="list" then
   if x>e.x and y>e.y and x<e.x+e.sizeX and y<e.y+e.sizeY then
    gui.focus=i
    gui.list.mouseDown(e,x-e.x,y-e.y)
   end
  elseif e[1]=="textBox" then
   if x>e.x and y>e.y and x<e.x+e.sizeX and y<e.y+22 then
    gui.focus=i
    gui.textBox.mouseDown(e,x-e.x,y-e.y)
   end
  elseif e[1]=="colorSlider" then
   if x>e.x and y>e.y and x<e.x+68 and y<e.y+20 then
    gui.focus=i
    gui.colorSlider.mouseDown(e,x-e.x,y-e.y)
   end
  end
 end
 gui.refreshCurrent()
end



--GUI DRAWING

function gui.dialogBox.paint(gc,dialogBox,windowID)
 local sizeX,sizeY
 if not dialogBox.size then
  gc:setFont("sansserif","r",10)
  sizeX=improvedStr.width(gc,dialogBox.layout)+24
  sizeY=improvedStr.height(gc,dialogBox.layout)+17
  gui.windows[windowID].size={sizeX,sizeY}
 else
  sizeX,sizeY=unpack(dialogBox.size)
 end
 gui.paintWindowBG(gc,dialogBox.name,sizeX,sizeY)
 gui.paintTextArea(gc,dialogBox.layout,sizeX,sizeY)
 gui.paintButtons(gc,dialogBox.buttons,sizeX,sizeY,windowID)
end

function gui.custom.paint(gc,window,windowID)
 gui.paintWindowBG(gc,window.name,window.size[1],window.size[2])
 gui.paintLayout(gc,window.layout,window.size[1],window.size[2])
 gui.paintButtons(gc,window.buttons,window.size[1],window.size[2],windowID)
end





function gui.paintLayout(gc,layout,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 for i,e in pairs(layout) do
  if e[1]=="textBox" then
   gui.paintTextBox(gc,e,x,y,gui.focus==i)
  elseif e[1]=="label" then
   gui.paintLabel(gc,e,x,y)
  elseif e[1]=="colorSlider" then
   gui.paintColorSlider(gc,e,x,y,gui.focus==i)
  elseif e[1]=="list" then
   gui.paintList(gc,e,x,y,gui.focus==i)
  end
 end
end

function gui.paintLabel(gc,label,x,y)
 gc:setFont("sansserif","r",10)
 if label.text=="colorLabel" then
  gc:setColorRGB(0,0,0)
  gc:fillRect(x+label.x,y+label.y,30,20)
  gc:setColorRGB(unpack(color))
  gc:fillRect(x+label.x+1,y+label.y+1,28,18)
 else
  gc:setColorRGB(0,0,0)
  gc:drawString(label.text,x+label.x,y+label.y,"top")
 end
end

function gui.paintTextBox(gc,textBox,x,y,selected)
 if gc:getStringWidth(textBox.text)>textBox.sizeX-5 then
  textBox.prev=textBox.prev or {"",0}
  textBox.text,textBox.cursor=unpack(textBox.prev)
 end
 if textBox.setCursor then
  textBox.cursor=string.len(textBox.text)
  for i=string.len(textBox.text),1,-1 do
   if gc:getStringWidth(string.sub(textBox.text,1,i))>textBox.setCursor then
    textBox.cursor=i-1
   end
  end
  textBox.setCursor=nil
 end
 if selected then
  gc:setColorRGB(50,150,190)
  gc:fillRect(x+textBox.x-2,y+textBox.y-2,textBox.sizeX+5,27)
 end
 gc:setColorRGB(255,255,255)
 gc:fillRect(x+textBox.x,y+textBox.y,textBox.sizeX,22)
 gc:setColorRGB(0,0,0)
 gc:drawRect(x+textBox.x,y+textBox.y,textBox.sizeX,22)
 gc:setFont("sansserif","r",10)
 gc:drawString(textBox.text,x+textBox.x+3,y+textBox.y+1,"top")
 if selected then
  gc:fillRect(gc:getStringWidth(string.usub(textBox.text,1,textBox.cursor))+x+textBox.x+3,y+textBox.y+2,1,19)
 end
end

function gui.paintColorSlider(gc,slider,x,y,selected)
 if selected then
  gc:setColorRGB(50,150,190)
  gc:fillRect(x+slider.x-2,y+slider.y-2,72,24)
 end
 gc:setColorRGB(0,0,0)
 gc:fillRect(x+slider.x,y+slider.y,68,20)
 for i=0,63 do
  gc:setColorRGB(slider.color=="red" and i*4 or color[1],slider.color=="green" and i*4 or color[2],slider.color=="blue" and i*4 or color[3])
  gc:fillRect(x+slider.x+i+2,y+2+slider.y,1,16)
 end
 if isCX() then
  gc:setColorRGB(255-slider.value,255-slider.value,255-slider.value)
 else
  gc:setColorRGB(255,255,255)
 end
 gc:fillRect(x+slider.x+slider.value/4+1,y+slider.y-2,3,24)
end

function gui.paintList(gc,list,x,y,selected)
 if selected then
  gc:setColorRGB(50,150,190)
  gc:fillRect(x+list.x-2,y+list.y-2,list.sizeX+4,list.sizeY+4)
 end
 gc:setColorRGB(0,0,0)
 gc:fillRect(list.x+x,list.y+y,list.sizeX,list.sizeY)
 gc:setColorRGB(255,255,255)
 gc:fillRect(list.x+1+x,list.y+1+y,list.sizeX-2,list.sizeY-2)
 gc:setColorRGB(100,100,100)
 gc:drawImage(gui.img.upButton,list.x+x+list.sizeX-14,y+list.y+3)
 gc:drawImage(gui.img.downButton,list.x+x+list.sizeX-14,y+list.y+list.sizeY-13)
 gc:drawRect(list.x+x+list.sizeX-14,y+list.y+15,10,list.sizeY-31)
 gc:setFont("sansserif","r",10)
 local fontHeight=gc:getStringHeight("a")
 local capacity=math.floor(list.sizeY/fontHeight)
 if list.setSelection then
  list.selected=math.floor(list.setSelection/fontHeight)+1+list.scroll
  list.selected=list.selected<#list.elements and list.selected or #list.elements
  list.setSelection=nil
 end
 if list.selected<list.scroll+1 then
  list.scroll=list.selected-1
 elseif list.selected>list.scroll+capacity then
  list.scroll=list.selected-capacity
 end
 if list.scroll>#list.elements-capacity then
  local scroll=#list.elements-capacity
  scroll=scroll<0 and 0 or scroll
  list.scroll=scroll
 end
 if #list.elements*fontHeight>list.sizeY then
  local scrollBarSize=(list.sizeY-31)*list.sizeY/(#list.elements*fontHeight)
  gc:fillRect(list.x+x+list.sizeX-14,y+list.y+15+list.scroll*(list.sizeY-31)/#list.elements,11,scrollBarSize)
 end
 gc:setColorRGB(0,0,0)
 local step=0
 for i=list.scroll+1,list.scroll+capacity do
  if list.elements[i] then
   if list.selected==i then
    gc:setColorRGB(50,150,190)
    gc:fillRect(list.x+x+1,list.y+y+step*fontHeight+1,list.sizeX-16,fontHeight-2)
    gc:setColorRGB(0,0,0)
   end
   gc:drawString(list.elements[i],list.x+x+3,list.y+y+step*fontHeight,"top")
   step=step+1
  end
 end
end

function gui.paintButtons(gc,buttons,sizeX,sizeY,windowID)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 gc:setFont("sansserif","r",10)
 if (not buttons[1].size) or gui.resized then
  local totalSize,size,pos=-7,{},{}
  for i,e in pairs(buttons) do
   size[i]=gc:getStringWidth(e[1])+10
   totalSize=totalSize+size[i]+7
  end
  pos[1]=(width()-totalSize)/2
  for i=2,#buttons do
   pos[i]=pos[i-1]+size[i-1]+7
  end
  for i,e in pairs(buttons) do
   gui.windows[windowID].buttons[i].size=size[i]
   gui.windows[windowID].buttons[i].pos=pos[i]
  end
  buttons=gui.windows[windowID].buttons
 end
 for i,e in pairs(buttons) do
  gc:setColorRGB(136,136,136)
  gc:fillRect(e.pos,y+sizeY+9,e.size,23)
  gc:fillRect(e.pos+1,y+sizeY+8,e.size-2,25)
  gc:fillRect(e.pos+2,y+sizeY+7,e.size-4,27)
  gc:setColorRGB(255,255,255)
  gc:fillRect(e.pos+2,y+sizeY+9,e.size-4,23)
  gc:setColorRGB(0,0,0)
  gc:drawString(e[1],e.pos+5,y+sizeY+20,"middle")
 end
 if gui.focus<0 and windowID==gui.nbWindows() then
  local button=buttons[-gui.focus]
  if isCX() then
   gc:setColorRGB(50,150,190)
  else
   gc:setColorRGB(0,0,0)
  end
  gc:drawRect(button.pos-3,y+sizeY+4,button.size+5,32)
  gc:drawRect(button.pos-2,y+sizeY+5,button.size+3,30)
 end
end

function gui.paintTextArea(gc,text,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 if isCX() then
  gc:setColorRGB(128,128,128)
 else
  gc:setColorRGB(255,255,255)
 end
 gc:drawRect(x+6,y+6,sizeX-13,sizeY-13)
 gc:setColorRGB(0,0,0)
 gc:setFont("sansserif","r",10)
 improvedStr.draw(gc,text,x+12,y+9)
end

function gui.paintWindowBG(gc,name,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 if isCX() then
  gc:setColorRGB(100,100,100)
 else
  gc:setColorRGB(200,200,200)
 end
 gc:fillRect(x-1,y-23,sizeX+4,sizeY+65)
 gc:fillRect(x,y-22,sizeX+4,sizeY+65)
 gc:fillRect(x+1,y-21,sizeX+4,sizeY+65)
 if isCX() then
  gc:setColorRGB(128,128,128)
 else
  gc:setColorRGB(0,0,0)
 end
 gc:fillRect(x-2,y-24,sizeX+4,sizeY+65)
 if isCX() then
  for i=1,22 do
   gc:setColorRGB(32+i*3,32+i*3,32+i*3)
   gc:fillRect(x,y+i-23,sizeX,1)
  end
 else
  gc:setColorRGB(0,0,0)
  gc:fillRect(x,y-22,sizeX,22)
 end
 gc:setColorRGB(255,255,255)
 gc:setFont("sansserif","r",10)
 gc:drawString(name,x+2,y-9,"baseline")
 gc:setColorRGB(224,224,224)
 gc:fillRect(x,y,sizeX,sizeY+39)
 gc:setColorRGB(128,128,128)
 gc:fillRect(x+6,y+sizeY,sizeX-12,2)
end





--MULTIPLE LINE STRING GESTION
improvedStr={}

function improvedStr.draw(gc,str,x,y)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 for i,e in pairs(table1) do
  gc:drawString(e,x,y+(i-1)*gc:getStringHeight("a"),"top")
 end
end

function improvedStr.width(gc,str)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 local table2={}
 for i,e in pairs(table1) do
  table2[i]=gc:getStringWidth(e)
 end
 table.sort(table2)
 return table2[#table2]
end

function improvedStr.height(gc,str)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 return gc:getStringHeight("a")*#table1
end

function improvedStr.cut(str)
 local table1,finished={},false
 local posStart,posEnd,last=1,0,1
 while not finished do
  posStart,posEnd=string.find(str,"\n",posEnd+1)
  if posStart then
   table.insert(table1,string.sub(str,last,posStart-1))
   last=posEnd+1
  else
   table.insert(table1,string.sub(str,last))
   finished=true
  end
 end
 return unpack(table1)
end


















color={0,255,0}
 
function width() return platform.window:width() end
function height() return platform.window:height() end
function isCX() return platform.isColorDisplay() end
function refresh(x,y,width,height) platform.window:invalidate(x,y,width,height) end
 
function openCustom()
 gui.addWindow("custom","custom",{{"Close",function() gui.closeWindow() end}},{{"label",text="Hello !",x=15,y=5},{"textBox",text="type here",cursor=3,x=10,y=30,sizeX=80},{"colorSlider",color="red",value=200,x=15,y=70},{"list",x=100,y=10,sizeX=70,sizeY=80,scroll=0,selected=1,elements={"elem a","elem b","elem c","elem d","elem e","elem f","another","...","Blue","Yellow","Green"}}},{200,100})
end

gui.addWindow("dialogBox","Title",{{"Error message",function() gui.errorMessage("Error test") end},{"Open custom window",function() openCustom() end}},"This text shows multi-line text functions :\nLorem ipsum dolor sit amet\n...")

function on.paint(gc)
 gui.paint(gc)
end

function on.mouseDown(x,y)
 gui.mouseDown(x,y)
end

function on.resize()
 gui.resize()
end

function on.tabKey()
 gui.tabKey()
end

function on.backtabKey()
 gui.backtabKey()
end

function on.enterKey()
 gui.enterKey()
end

function on.arrowKey(ar)
 gui.arrowKey(ar)
end

function on.charIn(ch)
 gui.charIn(ch)
end

function on.escapeKey()
 gui.escapeKey()
end

function on.backspaceKey()
 gui.backspaceKey()
end
And a screenie is attached.
Title: Re: [Lua] Image Editor
Post by: Deep Toaster on January 27, 2012, 06:46:55 pm
That UI looks great ... almost native :o Nice job! Should the titles be shifted over a bit, though?
Title: Re: [Lua] Image Editor
Post by: Chockosta on January 28, 2012, 06:59:34 am
You're right, I just modified that.

Right now I'm busy integrating it to nSpaint...
It should be released next week.
Title: Re: [Lua] Image Editor
Post by: apcalc on January 29, 2012, 08:43:34 pm
That UI looks great ... almost native :o Nice job! Should the titles be shifted over a bit, though?

Agreed, it looks great! ;)
Title: Re: [Lua] Image Editor
Post by: Chockosta on April 11, 2012, 12:33:28 pm
I don't know if anyone still use this, but I just finished it.
(I spent too much time on this to give up)

So, here is nSpaint 0.7. It features :


-The same tools and filters as in nSpaint 0.6
-A native-like GUI (in nAnima too)
-A file manager, which can be used to delete images (in nAnima too)
-A tool to copy the current image code to the clipboard (really useful to Lua developpers!)
-A tool to paste an image if there's one in the clipboard
-Undo and redo! (5 times max)
-A option to erase all the image
-A nice color selecter
-Tools to flip/rotate the image
-A filter which replace a color with another one
-A filter which erases a color
-Two filters to increase and decrease brightness
-A 'help' window for each tool
-A splash screen (in nAnima too)
-You can move the cursor with the mouse
-The image is automatically moved when the cursor goes off the screen
-The cursor is moved when you scroll

DOWNLOAD (http://www.omnimaga.org/index.php?action=dlattach;topic=9821.0;attach=12450)

Screenies:
(http://i45.servimg.com/u/f45/11/25/11/26/screen26.png)

Title: Re: [Lua] Image Editor
Post by: Jonius7 on April 11, 2012, 12:38:59 pm
Wow I was definitely not aware of this. This looks mega useful and very graphical too. How do you get those dialogue boxes up?
Title: Re: [Lua] Image Editor
Post by: Chockosta on April 11, 2012, 12:46:45 pm
I created a GUI lib which imitates TI's one...
But if you want to use it, I have to warn you : It will not be easy at all to use in your code.
Here is its code :
Code: [Select]

----------------------------------------------------------------------------------------------------
------------------------  Nspaint GUI engine by Loic Pujet (Chockosta) -----------------------------
----------------------------------------------------------------------------------------------------

--[[
window : {wtype,name,buttons,layout,size}
   --> wtype : "dialogBox","custom"
   --> size : {sizeX,sizeY} (only for custom)

buttons : {{"name",function1},{"name",function2},...}

layout : {{"type",...}}
   --> type : "label","textBox","colorSlider","list"

label : {text,x,y,color}
   --> if color is given, a color label is displayed

textBox : {text,x,y,sizeX,cursor,func}

colorSlider : {color,value,x,y,func}
   --> color : "red","green","blue"

list : {elements,scroll,x,y,sizeX,sizeY,selected,func}  ]]


--GUI DATA
gui={}
gui.windows={}
gui.dialogBox={}
gui.custom={}
gui.textBox={}
gui.colorSlider={}
gui.list={}
gui.resized=false
gui.img={}
gui.img.upButton=image.new("\011\000\000\000\010\000\000\000\000\000\000\000\022\000\000\000\016\000\001\0001\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\198\255\255\255\255\255\255\255\255\156\243\255\255\255\255\255\255\255\2551\1981\198\255\255\255\255\255\255\214\218\000\128\214\218\255\255\255\255\255\2551\1981\198\255\255\255\255\247\222B\136\000\128B\136\247\222\255\255\255\2551\1981\198\255\255\247\222B\136!\132\000\128!\132B\136\247\222\255\2551\1981\198\247\222B\136!\132B\136R\202B\136!\132B\136\247\2221\1981\198\132\144B\136B\136\247\222\255\255\247\222B\136B\136\132\1441\1981\198\156\243\132\144\247\222\255\255\255\255\255\255\247\222\132\144\189\2471\1981\198\255\255\222\251\255\255\255\255\255\255\255\255\255\255\222\251\255\2551\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\198")
gui.img.downButton=image.new("\011\000\000\000\010\000\000\000\000\000\000\000\022\000\000\000\016\000\001\0001\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\198\255\255\222\251\255\255\255\255\255\255\255\255\255\255\222\251\255\2551\1981\198\156\243\132\144\247\222\255\255\255\255\255\255\247\222\132\144\189\2471\1981\198\132\144B\136B\136\247\222\255\255\247\222B\136B\136\132\1441\1981\198\247\222B\136!\132B\136R\202B\136!\132B\136\247\2221\1981\198\255\255\247\222B\136!\132\000\128!\132B\136\247\222\255\2551\1981\198\255\255\255\255\247\222B\136\000\128B\136\247\222\255\255\255\2551\1981\198\255\255\255\255\255\255\214\218\000\128\214\218\255\255\255\255\255\2551\1981\198\255\255\255\255\255\255\255\255\156\243\255\255\255\255\255\255\255\2551\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\1981\198")



--------------------------------------------------------------------------------------------------------------
--------------------------------------------- USER FUNCTIONS -------------------------------------------------
--------------------------------------------------------------------------------------------------------------

function gui.errorMessage(errorText)
 gui.addWindow("dialogBox","Error",{{"OK",function() gui.closeWindow() end}},errorText)
end

function gui.addTextWindow(title,text)
 gui.addWindow("dialogBox",title,{},text)
end

function gui.addCustomWindow(title,width,height)
 gui.addWindow("custom",title,{},{},{width,height})
end

function gui.addButton(text,buttonFunction)
 table.insert(gui.current().buttons,{text,buttonFunction})
end

function gui.addTextBox(xPos,yPos,width,initialText,textBoxFunction)
 if gui.current().wtype=="custom" then
  table.insert(gui.current().layout,{"textBox",text=initialText,x=xPos,y=yPos,sizeX=width,cursor=0,func=textBoxFunction})
 end
end

function gui.addLabel(xPos,yPos,labelText,labelColor)
 if gui.current().wtype=="custom" then
  table.insert(gui.current().layout,{"label",text=labelText,x=xPos,y=yPos,color=labelColor})
 end
end

function gui.addSlider(xPos,yPos,sliderColor,initialValue,sliderFunction)
 if gui.current().wtype=="custom" then
  table.insert(gui.current().layout,{"colorSlider",value=initialValue,x=xPos,y=yPos,color=sliderColor,func=sliderFunction})
 end
end

function gui.addList(xPos,yPos,width,height,listElements,listFunction)
 if gui.current().wtype=="custom" then
  table.insert(gui.current().layout,{"list",x=xPos,y=yPos,sizeX=width,sizeY=height,scroll=0,selected=1,elements=listElements,func=listFunction})
 end
end

function gui.closeWindow()
 table.remove(gui.windows)
 gui.defaultFocus()
 refresh()
end

function gui.nbWindows()
 return #gui.windows
end

function gui.defaultFocus()
 if gui.nbWindows()>0 then
  gui.focus=-#gui.current().buttons
  gui.moveFocus(1)
  gui.focus=gui.focus>0 and gui.focus or -1
 end
end


--------------------------------------------------------------------------------------------------------------
--------------------------------------------END OF USER FUNCTIONS---------------------------------------------
--------------------------------------------------------------------------------------------------------------



--GUI UTILS

function gui.refreshCurrent()
 local current=gui.current()
 if current.size then
  local sizeX,sizeY=unpack(current.size)
  local xPos,yPos=(width()-sizeX)/2,(height()-sizeY-15)/2
  refresh(xPos,yPos,sizeX,sizeY+39)
 else
  refresh()
 end
end

function gui.addWindow(windowType,windowName,windowButtons,windowLayout,windowSize)
 table.insert(gui.windows,{wtype=windowType,name=windowName,buttons=windowButtons,layout=windowLayout,size=windowSize})
 gui.focus=-1
 refresh()
end

function gui.current()
 return gui.windows[#gui.windows]
end



--GUI EVENTS
function gui.mouseDown(xPos,yPos)
 if gui.nbWindows()>=1 then
  local window=gui.current()
  if window.size then
   local sizeX,sizeY=unpack(window.size)
   local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
   if xPos>x and xPos<x+sizeX and yPos>y then
    gui.saveTextBox()
    if yPos<y+sizeY and gui.current().wtype=="custom" then
     gui.setFocus(xPos-x,yPos-y,window)
    elseif yPos>y+sizeY and yPos<y+sizeY+39 then
     gui.buttonDown(xPos,yPos,window.buttons)
    end
   end
  end
 end
end

function gui.paint(gc)
 for i,e in pairs(gui.windows) do
  gui[e.wtype].paint(gc,e,i)
 end
 gui.resized=false
end

function gui.resize()
 gui.resized=true
end

function gui.tabKey()
 if gui.nbWindows()>0 then
  gui.saveTextBox()
  gui.moveFocus(1)
  gui.refreshCurrent()
 end
end

function gui.backtabKey()
 if gui.nbWindows()>0 then
  gui.saveTextBox()
  gui.moveFocus(-1)
  gui.refreshCurrent()
 end
end

function gui.arrowKey(arrow)
 if gui.nbWindows()>0 then
  if gui.focus<0 then
   if arrow=="left" then
    gui.moveFocus(-1)
    gui.refreshCurrent()
   elseif arrow=="right" then
    gui.moveFocus(1)
    gui.refreshCurrent()
   end
  elseif gui.focus>0 then
   local currentElem=gui.current().layout[gui.focus]
   if gui[currentElem[1]].arrowKey then
    gui[currentElem[1]].arrowKey(arrow,currentElem)
    gui.refreshCurrent()
   end
  end
 end
end

function gui.enterKey()
 if gui.nbWindows()>0 then
  if gui.focus<0 then
   gui.current().buttons[-gui.focus][2]()
  elseif gui.current().wtype=="custom" then
   gui.OKButton()
  end
 end
end

function gui.charIn(char)
 if gui.nbWindows()>0 then
  if gui.focus>0 then
   local currentElem=gui.current().layout[gui.focus]
   if gui[currentElem[1]].charIn then
    gui[currentElem[1]].charIn(char,currentElem)
    gui.refreshCurrent()
   end
  end
 end
end

function gui.backspaceKey()
 if gui.nbWindows()>0 then
  if gui.focus>0 then
   local currentElem=gui.current().layout[gui.focus]
   if gui[currentElem[1]].backspaceKey then
    gui[currentElem[1]].backspaceKey(currentElem)
    gui.refreshCurrent()
   end
  end
 end
end

function gui.escapeKey()
 if gui.nbWindows()>0 then
  gui.closeWindow()
 end
end



--GUI LAYOUT ELEMENTS EVENTS

function gui.textBox.charIn(char,textBox)
 if string.len(char)==1 then
  textBox.prev={textBox.text,textBox.cursor}
  textBox.text=string.usub(textBox.text,1,textBox.cursor)..char..string.usub(textBox.text,textBox.cursor+1)
  textBox.cursor=textBox.cursor+1
 end
end

function gui.textBox.arrowKey(arrow,textBox)
 if arrow=="right" and textBox.cursor<string.len(textBox.text) then
  textBox.cursor=textBox.cursor+1
 elseif arrow=="left" and textBox.cursor>0 then
  textBox.cursor=textBox.cursor-1
 end
end

function gui.textBox.mouseDown(textBox,x)
 textBox.setCursor=x-2
end

function gui.textBox.backspaceKey(textBox)
 if string.len(textBox.text)>0 and textBox.cursor>0 then
  textBox.text=string.usub(textBox.text,1,textBox.cursor-1)..string.usub(textBox.text,textBox.cursor+1)
  textBox.cursor=textBox.cursor-1
 end
end

function gui.colorSlider.arrowKey(arrow,slider)
 if arrow=="right" then
  slider.value=slider.value<250 and slider.value+5 or 255
  gui.executeFunction(slider,slider.value)
 elseif arrow=="left" then
  slider.value=slider.value>5 and slider.value-5 or 0
  gui.executeFunction(slider,slider.value)
 end
end

function gui.colorSlider.mouseDown(slider,x)
 x=(x-2)*4
 x=x>0 and x or 0
 x=x<255 and x or 255
 slider.value=x
 gui.executeFunction(slider,slider.value)
end

function gui.list.arrowKey(arrow,list)
 if arrow=="up" and list.selected>1 then
  list.selected=list.selected-1
  gui.executeFunction(list,list.elements[list.selected])
 elseif arrow=="down" and list.selected<#list.elements then
  list.selected=list.selected+1
  gui.executeFunction(list,list.elements[list.selected])
 end
end

function gui.list.mouseDown(list,x,y)
 if #list.elements>0 then
  if x>list.sizeX-17 then
   if y>list.sizeY/2 and list.selected<#list.elements then
    list.selected=list.selected+1
    gui.executeFunction(list,list.elements[list.selected])
   elseif y<list.sizeY/2 and list.selected>1 then
    list.selected=list.selected-1
    gui.executeFunction(list,list.elements[list.selected])
   end
  elseif list.fontHeight  then
   list.selected=math.floor(y/list.fontHeight)+1+list.scroll
   list.selected=list.selected<#list.elements and list.selected or #list.elements
   gui.executeFunction(list,list.elements[list.selected])
  end
 end
end


--GUI MISC FUNCTIONS

function gui.executeFunction(element,arg)
 if element.func then
  element.func(arg)
 end
end

function gui.saveTextBox()
 local elem=gui.current().layout[gui.focus]
 if elem then
  if elem[1]=="textBox" then
   gui.executeFunction(elem,elem.text)
  end
 end
end

function gui.moveFocus(nb)
 local currentWindow=gui.current()
 local test=false
 local originalFocus=gui.focus
 nb=gui.focus<0 and -nb or nb
 gui.focus=gui.focus+nb
 if #currentWindow.buttons==0 then
  gui.focus=-1
  test=true
 end
 while not test do
  if gui.focus<0 then
   if -gui.focus<=#currentWindow.buttons then
    test=true
   else
    gui.focus=1
    nb=1
   end
  elseif gui.focus==0 then
   if originalFocus<0 then
    if currentWindow.wtype=="dialogBox" then
     gui.focus=-#currentWindow.buttons
     test=true
    elseif #currentWindow.layout==0 then
     gui.focus=-#currentWindow.buttons
     test=true
    else
     gui.focus=#currentWindow.layout
     nb=-1
    end
   else
    gui.focus=nb<0 and -#currentWindow.buttons or 1
   end
  else
   if currentWindow.wtype=="dialogBox" then
    test=true
    gui.focus=-1
   elseif currentWindow.wtype=="custom" then
    if gui.focus<=#currentWindow.layout then
     if currentWindow.layout[gui.focus][1]=="label" then
      gui.focus=gui.focus+(nb<0 and -1 or 1)
     else
      test=true
     end
    else
     test=true
     gui.focus=-1
    end
   end
  end
 end
end

function gui.buttonDown(x,y,buttons)
 for i,e in pairs(buttons) do
  if x>e.pos and x<e.pos+e.size then
   gui.focus=-i
   e[2]()
  end
 end
end

function gui.OKButton()
 local buttons=gui.current().buttons
 for i=1,#buttons do
  if buttons[i][1]=="OK" then
   gui.saveTextBox()
   buttons[i][2]()
  end
 end
end

function gui.setFocus(x,y,window)
 for i,e in pairs(window.layout) do
  if e[1]=="list" then
   if x>e.x and y>e.y and x<e.x+e.sizeX and y<e.y+e.sizeY then
    gui.focus=i
    gui.list.mouseDown(e,x-e.x,y-e.y)
    gui.refreshCurrent()
   end
  elseif e[1]=="textBox" then
   if x>e.x and y>e.y and x<e.x+e.sizeX and y<e.y+22 then
    gui.focus=i
    gui.textBox.mouseDown(e,x-e.x,y-e.y)
    gui.refreshCurrent()
   end
  elseif e[1]=="colorSlider" then
   if x>e.x and y>e.y and x<e.x+68 and y<e.y+20 then
    gui.focus=i
    gui.colorSlider.mouseDown(e,x-e.x,y-e.y)
    gui.refreshCurrent()
   end
  end
 end
end



--GUI DRAWING

function gui.dialogBox.paint(gc,dialogBox,windowID)
 local sizeX,sizeY
 if not dialogBox.size then
  gc:setFont("sansserif","r",10)
  sizeX=improvedStr.width(gc,dialogBox.layout)+24
  sizeY=improvedStr.height(gc,dialogBox.layout)+17
  gui.windows[windowID].size={sizeX,sizeY}
 else
  sizeX,sizeY=unpack(dialogBox.size)
 end
 gui.paintWindowBG(gc,dialogBox.name,sizeX,sizeY)
 gui.paintTextArea(gc,dialogBox.layout,sizeX,sizeY)
 gui.paintButtons(gc,dialogBox.buttons,sizeX,sizeY,windowID)
end

function gui.custom.paint(gc,window,windowID)
 gui.paintWindowBG(gc,window.name,window.size[1],window.size[2])
 gui.paintLayout(gc,window.layout,window.size[1],window.size[2])
 gui.paintButtons(gc,window.buttons,window.size[1],window.size[2],windowID)
end





function gui.paintLayout(gc,layout,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 for i,e in pairs(layout) do
  if e[1]=="textBox" then
   gui.paintTextBox(gc,e,x,y,gui.focus==i)
  elseif e[1]=="label" then
   gui.paintLabel(gc,e,x,y)
  elseif e[1]=="colorSlider" then
   gui.paintColorSlider(gc,e,x,y,gui.focus==i)
  elseif e[1]=="list" then
   gui.paintList(gc,e,x,y,gui.focus==i)
  end
 end
end

function gui.paintLabel(gc,label,x,y)
 gc:setFont("sansserif","r",10)
 if label.color then
  gc:setColorRGB(0,0,0)
  gc:fillRect(x+label.x,y+label.y,30,20)
  gc:setColorRGB(unpack(label.color))
  gc:fillRect(x+label.x+1,y+label.y+1,28,18)
 else
  gc:setColorRGB(0,0,0)
  gc:drawString(label.text,x+label.x,y+label.y,"top")
 end
end

function gui.paintTextBox(gc,textBox,x,y,selected)
 if gc:getStringWidth(textBox.text)>textBox.sizeX-5 then
  textBox.prev=textBox.prev or {"",0}
  textBox.text,textBox.cursor=unpack(textBox.prev)
 end
 if textBox.setCursor then
  textBox.cursor=string.len(textBox.text)
  for i=string.len(textBox.text),1,-1 do
   if gc:getStringWidth(string.sub(textBox.text,1,i))>textBox.setCursor then
    textBox.cursor=i-1
   end
  end
  textBox.setCursor=nil
 end
 if selected then
  gc:setColorRGB(50,150,190)
  gc:fillRect(x+textBox.x-2,y+textBox.y-2,textBox.sizeX+5,27)
 end
 gc:setColorRGB(255,255,255)
 gc:fillRect(x+textBox.x,y+textBox.y,textBox.sizeX,22)
 gc:setColorRGB(0,0,0)
 gc:drawRect(x+textBox.x,y+textBox.y,textBox.sizeX-1,22)
 gc:setFont("sansserif","r",10)
 gc:drawString(textBox.text,x+textBox.x+3,y+textBox.y+1,"top")
 if selected then
  gc:fillRect(gc:getStringWidth(string.usub(textBox.text,1,textBox.cursor))+x+textBox.x+3,y+textBox.y+2,1,19)
 end
end

function gui.paintColorSlider(gc,slider,x,y,selected)
 if selected then
  gc:setColorRGB(50,150,190)
  gc:fillRect(x+slider.x-2,y+slider.y-2,72,24)
 end
 gc:setColorRGB(0,0,0)
 gc:fillRect(x+slider.x,y+slider.y,68,20)
 for i=0,63 do
  gc:setColorRGB(slider.color=="red" and i*4 or newColor[1],slider.color=="green" and i*4 or newColor[2],slider.color=="blue" and i*4 or newColor[3])
  gc:fillRect(x+slider.x+i+2,y+2+slider.y,1,16)
 end
 if isCX() then
  gc:setColorRGB(255-slider.value,255-slider.value,255-slider.value)
 else
  gc:setColorRGB(255,255,255)
 end
 gc:fillRect(x+slider.x+slider.value/4+1,y+slider.y-2,3,24)
end

function gui.paintList(gc,list,x,y,selected)
 if selected then
  gc:setColorRGB(50,150,190)
  gc:fillRect(x+list.x-2,y+list.y-2,list.sizeX+4,list.sizeY+4)
 end
 gc:setColorRGB(0,0,0)
 gc:fillRect(list.x+x,list.y+y,list.sizeX,list.sizeY)
 gc:setColorRGB(255,255,255)
 gc:fillRect(list.x+1+x,list.y+1+y,list.sizeX-2,list.sizeY-2)
 gc:setColorRGB(100,100,100)
 gc:drawImage(gui.img.upButton,list.x+x+list.sizeX-14,y+list.y+3)
 gc:drawImage(gui.img.downButton,list.x+x+list.sizeX-14,y+list.y+list.sizeY-13)
 gc:drawRect(list.x+x+list.sizeX-14,y+list.y+15,10,list.sizeY-31)
 gc:setFont("sansserif","r",10)
 local fontHeight=list.fontHeight
 if not fontHeight then
  list.fontHeight=gc:getStringHeight("a")
  fontHeight=list.fontHeight
 end
 local capacity=math.floor(list.sizeY/fontHeight)
 if list.selected<list.scroll+1 then
  list.scroll=list.selected-1
 elseif list.selected>list.scroll+capacity then
  list.scroll=list.selected-capacity
 end
 if list.scroll>#list.elements-capacity then
  local scroll=#list.elements-capacity
  scroll=scroll<0 and 0 or scroll
  list.scroll=scroll
 end
 if #list.elements*fontHeight>list.sizeY then
  local scrollBarSize=(list.sizeY-31)*list.sizeY/(#list.elements*fontHeight)
  gc:fillRect(list.x+x+list.sizeX-14,y+list.y+15+list.scroll*(list.sizeY-31)/#list.elements,11,scrollBarSize)
 end
 gc:setColorRGB(0,0,0)
 local step=0
 for i=list.scroll+1,list.scroll+capacity do
  if list.elements[i] then
   if list.selected==i then
    gc:setColorRGB(unpack(selected and {50,150,190} or {200,200,200}))
    gc:fillRect(list.x+x+1,list.y+y+step*fontHeight+1,list.sizeX-16,fontHeight-2)
    gc:setColorRGB(0,0,0)
   end
   gc:drawString(list.elements[i],list.x+x+3,list.y+y+step*fontHeight,"top")
   step=step+1
  end
 end
end

function gui.paintButtons(gc,buttons,sizeX,sizeY,windowID)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 gc:setFont("sansserif","r",10)
 if (not buttons[1].size) or gui.resized then
  local totalSize,size,pos=-7,{},{}
  for i,e in pairs(buttons) do
   size[i]=gc:getStringWidth(e[1])+10
   totalSize=totalSize+size[i]+7
  end
  pos[1]=(width()-totalSize)/2
  for i=2,#buttons do
   pos[i]=pos[i-1]+size[i-1]+7
  end
  for i,e in pairs(buttons) do
   gui.windows[windowID].buttons[i].size=size[i]
   gui.windows[windowID].buttons[i].pos=pos[i]
  end
  buttons=gui.windows[windowID].buttons
 end
 for i,e in pairs(buttons) do
  gc:setColorRGB(136,136,136)
  gc:fillRect(e.pos,y+sizeY+9,e.size,23)
  gc:fillRect(e.pos+1,y+sizeY+8,e.size-2,25)
  gc:fillRect(e.pos+2,y+sizeY+7,e.size-4,27)
  gc:setColorRGB(255,255,255)
  gc:fillRect(e.pos+2,y+sizeY+9,e.size-4,23)
  gc:setColorRGB(0,0,0)
  gc:drawString(e[1],e.pos+5,y+sizeY+20,"middle")
 end
 if gui.focus<0 and windowID==gui.nbWindows() then
  local button=buttons[-gui.focus]
  if isCX() then
   gc:setColorRGB(50,150,190)
  else
   gc:setColorRGB(0,0,0)
  end
  gc:drawRect(button.pos-3,y+sizeY+4,button.size+5,32)
  gc:drawRect(button.pos-2,y+sizeY+5,button.size+3,30)
 end
end

function gui.paintTextArea(gc,text,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 if isCX() then
  gc:setColorRGB(128,128,128)
 else
  gc:setColorRGB(255,255,255)
 end
 gc:drawRect(x+6,y+6,sizeX-13,sizeY-13)
 gc:setColorRGB(0,0,0)
 gc:setFont("sansserif","r",10)
 improvedStr.draw(gc,text,x+12,y+9)
end

function gui.paintWindowBG(gc,name,sizeX,sizeY)
 local x,y=(width()-sizeX)/2,(height()-sizeY-15)/2
 if isCX() then
  gc:setColorRGB(100,100,100)
 else
  gc:setColorRGB(200,200,200)
 end
 gc:fillRect(x-1,y-23,sizeX+4,sizeY+65)
 gc:fillRect(x,y-22,sizeX+4,sizeY+65)
 gc:fillRect(x+1,y-21,sizeX+4,sizeY+65)
 if isCX() then
  gc:setColorRGB(128,128,128)
 else
  gc:setColorRGB(0,0,0)
 end
 gc:fillRect(x-2,y-24,sizeX+4,sizeY+65)
 if isCX() then
  for i=1,22 do
   gc:setColorRGB(32+i*3,32+i*3,32+i*3)
   gc:fillRect(x,y+i-23,sizeX,1)
  end
 else
  gc:setColorRGB(0,0,0)
  gc:fillRect(x,y-22,sizeX,22)
 end
 gc:setColorRGB(255,255,255)
 gc:setFont("sansserif","r",10)
 gc:drawString(name,x+4,y-9,"baseline")
 gc:setColorRGB(224,224,224)
 gc:fillRect(x,y,sizeX,sizeY+39)
 gc:setColorRGB(128,128,128)
 gc:fillRect(x+6,y+sizeY,sizeX-12,2)
end




--MULTIPLE LINE STRING GESTION
improvedStr={}

function improvedStr.draw(gc,str,x,y)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 for i,e in pairs(table1) do
  gc:drawString(e,x,y+(i-1)*gc:getStringHeight("a"),"top")
 end
end

function improvedStr.width(gc,str)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 local table2={}
 for i,e in pairs(table1) do
  table2[i]=gc:getStringWidth(e)
 end
 table.sort(table2)
 return table2[#table2]
end

function improvedStr.height(gc,str)
 str=tostring(str)
 local table1={improvedStr.cut(str)}
 return gc:getStringHeight("a")*#table1
end

function improvedStr.cut(str)
 local table1,finished={},false
 local posStart,posEnd,last=1,0,1
 while not finished do
  posStart,posEnd=string.find(str,"\n",posEnd+1)
  if posStart then
   table.insert(table1,string.sub(str,last,posStart-1))
   last=posEnd+1
  else
   table.insert(table1,string.sub(str,last))
   finished=true
  end
 end
 return unpack(table1)
end


----------------------------------------------------------------------------------------------------
------------------------------------- End of Nspaint GUI engine ------------------------------------
----------------------------------------------------------------------------------------------------
Title: Re: [Lua] Image Editor
Post by: Adriweb on April 11, 2012, 12:54:25 pm
Very, very nice looking gui.

I wonder how it compares to EEPro's one in term of extensibility/power.
I know jim's way was amazing :P
Title: Re: [Lua] Image Editor
Post by: cyanophycean314 on April 12, 2012, 04:01:36 am
The long awaited update is here! The screenies look very pretty.  :D
Title: Re: [Lua] Image Editor
Post by: Yeong on April 12, 2012, 04:48:27 am
Wow this now looks epic! :o
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on April 12, 2012, 08:07:58 pm
Very nice work :)

I'm also working on a similar library for EEPro.
But my structure is a bit different than yours, it's closer to an actual graphical toolkit like gtk.
Your's will be much more lighter though, so that's also very good.
Title: Re: [Lua] Image Editor
Post by: Chockosta on April 12, 2012, 09:15:57 pm
Yes, my "library" is just a tool to make window display and events easier, not a graphical toolkit.
It is obviously way more basic than a real GUI engine.
By the way, is there a way to have a look at your library's code ?
EDIT : Oh, I just saw the link in your signature, sorry :)
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on April 12, 2012, 09:36:47 pm
The graphical libs are
Global Library/screen.lua and
Global Library/widgets.lua.

Right now I do not have so many widgets, but it is easy to add more. The part I am mainly focusing on is the structure.
Take a look at http://tiplanet.org/forum/archives_voir.php?id=4177, you can see how a very basic program works. (If you ignore the library code)
Title: Re: [Lua] Image Editor
Post by: Chockosta on April 13, 2012, 02:35:41 pm
Oh, I see.
Your way seems now really better than mine, good job :)

My GUI only allow to use widgets in a window, while with your one, you can put buttons or list wherever you want to.
Title: Re: [Lua] Image Editor
Post by: Jim Bauwens on April 13, 2012, 03:33:34 pm
Thanks :)

A nice thing too is that I have special widgets that can acts like a screenmanager, they can include other widgets.
This way you can create simple widgets and combine them to create advanced widgets.
Title: Re: [Lua] Image Editor
Post by: Alex on April 13, 2012, 08:39:38 pm
Nice work Chockosta.
Title: Re: [Lua] Image Editor
Post by: DJ Omnimaga on April 17, 2012, 09:15:11 pm
Nice to see this updated Chockosta, but you should use a less crappy host than imgserv, because it's down often. :P
Title: Re: [Lua] Image Editor
Post by: AzNg0d1030 on June 05, 2012, 08:11:54 pm
Tribute to Chockosta and nSpaint 0.7:
Title: Re: [Lua] Image Editor
Post by: Nick on June 05, 2012, 11:10:43 pm
wOw, that's nice :) it looks really good, impressive รถ
Title: Re: [Lua] Image Editor
Post by: Chockosta on June 06, 2012, 07:28:53 am
Great work, this is awesome !
Title: Re: [Lua] Image Editor
Post by: h4v0k3i on March 11, 2013, 10:13:30 pm
Is there a way I can view pictures that I add to my calculator?
Title: Re: [Lua] Image Editor
Post by: ElementCoder on March 12, 2013, 03:08:02 am
Not with this program iirc. You need to use either mViewer (http://ourl.ca/16645) for that, or use the TINCS to load images into text apps or as graph backgrounds. mViewer however requires ndless.
Title: Re: [Lua] Image Editor
Post by: h4v0k3i on March 12, 2013, 09:30:58 am
I saw a couple apps for ndless but I just got my nspire and have 3.2 on it. I figured I would try to find an app I could use without going back to 3.1
I scanned some notes from my math class and tried to put them into a document and it was not readable and I didn't know how to zoom.
Title: Re: [Lua] Image Editor
Post by: Hayleia on March 12, 2013, 09:41:45 am
Well for now, from what I read from your post, there are only drawbacks in staying with 3.2 :P
So why don't you downgrade and be able to view your images ?
Title: Re: [Lua] Image Editor
Post by: DJ Omnimaga on March 12, 2013, 03:20:47 pm
The only thing better about 3.2 for gamers is that Lua has a physical engine, which is used by some recent Lua programs, but other than that not much.