*/}}
Browse Source

Dummy save

Yiming Wu 1 year ago
parent
commit
0ea638f6db
2 changed files with 147 additions and 39 deletions
  1. 143 39
      ouroperations.c
  2. 4 0
      ourpaint.h

+ 143 - 39
ouroperations.c

@@ -57,6 +57,14 @@ void main() {\n\
 }\n\
 ";
 
+void our_CanvasAlphaMix(uint16_t* target, uint16_t* source){
+    real a_1=(real)(65535-source[3])/65535;
+    target[3]=source[3]+target[3]*a_1;
+    target[0]=source[0]+target[0]*a_1;
+    target[1]=source[1]+target[1]*a_1;
+    target[2]=source[2]+target[2]*a_1;
+}
+
 void our_InitsRGBProfile(int Linear, void** ptr, int* psize, char* copyright, char* manufacturer, char* description){
     cmsCIExyYTRIPLE srgb_primaries_pre_quantized = { {0.639998686, 0.330010138, 1.0}, {0.300003784, 0.600003357, 1.0}, {0.150002046, 0.059997204, 1.0} };
     cmsCIExyY d65_srgb_adobe_specs = {0.3127, 0.3290, 1.0};
@@ -148,19 +156,19 @@ void ourui_ToolsPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps
 
     laShowItem(uil,c,0,"our.tool")->Flags|=LA_UI_FLAGS_EXPAND;
     laUiItem* bt=laOnConditionThat(uil,c,laEqual(laPropExpression(0,"our.tool"),laIntExpression(OUR_TOOL_PAINT)));{
-        laUiItem* b=laOnConditionThat(uil,c,laPropExpression(0,"our.current_brush"));{
-            laShowItem(uil,c,0,"our.current_brush.name");
-            OUR_BR laShowItem(uil,c,0,"our.current_brush.size")->Expand=1; laShowItemFull(uil,c,0,"our.current_brush.pressure_size",0,"text=P",0,0); OUR_ER
-            OUR_BR laShowItem(uil,c,0,"our.current_brush.transparency")->Expand=1;  laShowItemFull(uil,c,0,"our.current_brush.pressure_transparency",0,"text=P",0,0); OUR_ER
-            OUR_BR laShowItem(uil,c,0,"our.current_brush.hardness")->Expand=1;  laShowItemFull(uil,c,0,"our.current_brush.pressure_hardness",0,"text=P",0,0); OUR_ER
-            OUR_BR laShowItem(uil,c,0,"our.current_brush.smudge")->Expand=1; laShowItemFull(uil,c,0,"our.current_brush.pressure_smudge",0,"text=P",0,0); OUR_ER
-            laShowItem(uil,c,0,"our.current_brush.dabs_per_size");
-            laShowItem(uil,c,0,"our.current_brush.smudge_resample_length");
+        laUiItem* b=laOnConditionThat(uil,c,laPropExpression(0,"our.tools.current_brush"));{
+            laShowItem(uil,c,0,"our.tools.current_brush.name");
+            OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.size")->Expand=1; laShowItemFull(uil,c,0,"our.tools.current_brush.pressure_size",0,"text=P",0,0); OUR_ER
+            OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.transparency")->Expand=1;  laShowItemFull(uil,c,0,"our.tools.current_brush.pressure_transparency",0,"text=P",0,0); OUR_ER
+            OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.hardness")->Expand=1;  laShowItemFull(uil,c,0,"our.tools.current_brush.pressure_hardness",0,"text=P",0,0); OUR_ER
+            OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.smudge")->Expand=1; laShowItemFull(uil,c,0,"our.tools.current_brush.pressure_smudge",0,"text=P",0,0); OUR_ER
+            laShowItem(uil,c,0,"our.tools.current_brush.dabs_per_size");
+            laShowItem(uil,c,0,"our.tools.current_brush.smudge_resample_length");
         }laEndCondition(uil,b);
 
         laShowLabel(uil,c,"Select a brush:",0,0);
 
-        laShowItemFull(uil,c,0,"our.brushes",0,0,0,0);
+        laShowItemFull(uil,c,0,"our.tools.brushes",0,0,0,0);
         laShowItem(uil,c,0,"OUR_new_brush");
     }laEndCondition(uil,bt);
 
@@ -304,7 +312,7 @@ void our_CanvasDrawOverlay(laUiItem* ui,int h){
 }
 
 OurLayer* our_NewLayer(char* name){
-    OurLayer* l=memAcquireHyper(sizeof(OurLayer)); strSafeSet(&l->Name,name); lstPushItem(&Our->Layers, l);
+    OurLayer* l=memAcquire(sizeof(OurLayer)); strSafeSet(&l->Name,name); lstPushItem(&Our->Layers, l);
     memAssignRef(Our, &Our->CurrentLayer, l);
     return l;
 }
@@ -380,19 +388,28 @@ void our_LayerEnsureTiles(OurLayer* ol, real xmin,real xmax, real ymin,real ymax
     }
     *tl=l; *tr=r; *tu=u; *tb=b;
 }
-void our_TileTextureToImage(OurTexTile* ot, int SX, int SY){
+void our_TileTextureToImage(OurTexTile* ot, int SX, int SY, int composite){
+    if(!ot->Texture) return;
     int bufsize=sizeof(uint16_t)*OUR_TEX_TILE_W_USE*OUR_TEX_TILE_W_USE*4;
     ot->Data=malloc(bufsize); int seam=OUR_TEX_TILE_SEAM; int width=OUR_TEX_TILE_W_USE;
     tnsBindTexture(ot->Texture);
     glPixelStorei(GL_PACK_ALIGNMENT, 2);
     glGetTextureSubImage(ot->Texture->GLTexHandle, 0, seam, seam, 0, width, width,1, GL_RGBA, GL_UNSIGNED_SHORT, bufsize, ot->Data);
-    int acc=0,read=0;
-    for(int row=0;row<OUR_TEX_TILE_W_USE;row++){
-        memcpy(&Our->ImageBuffer[((SY+row)*Our->ImageW+SX)*4],&ot->Data[(row*OUR_TEX_TILE_W_USE)*4],sizeof(uint16_t)*4*OUR_TEX_TILE_W_USE);
+    if(composite){
+        for(int row=0;row<OUR_TEX_TILE_W_USE;row++){
+            for(int col=0;col<OUR_TEX_TILE_W_USE;col++){
+                our_CanvasAlphaMix(&Our->ImageBuffer[((SY+row)*Our->ImageW+SX+col)*4], &ot->Data[(row*OUR_TEX_TILE_W_USE+col)*4]);
+            }
+        }
+    }else{
+        for(int row=0;row<OUR_TEX_TILE_W_USE;row++){
+            memcpy(&Our->ImageBuffer[((SY+row)*Our->ImageW+SX)*4],&ot->Data[(row*OUR_TEX_TILE_W_USE)*4],sizeof(uint16_t)*4*OUR_TEX_TILE_W_USE);
+        }
     }
     free(ot->Data); ot->Data=0;
 }
 void our_TileImageToTexture(OurTexTile* ot, int SX, int SY){
+    if(!ot->Texture) return;
     int pl=(SX!=0)?OUR_TEX_TILE_SEAM:0, pr=((SX+OUR_TEX_TILE_W_USE)!=Our->ImageW)?OUR_TEX_TILE_SEAM:0;
     int pu=(SY!=0)?OUR_TEX_TILE_SEAM:0, pb=((SY+OUR_TEX_TILE_W_USE)!=Our->ImageH)?OUR_TEX_TILE_SEAM:0;
     int bufsize=sizeof(uint16_t)*(OUR_TEX_TILE_W+pl+pr)*(OUR_TEX_TILE_W+pu+pb)*4;
@@ -424,11 +441,32 @@ int our_LayerEnsureImageBuffer(OurLayer* ol, int OnlyCalculate){
     }
     return 1;
 }
-void our_LayerToImageBuffer(OurLayer* ol){
+int our_CanvasEnsureImageBuffer(){
+    int x=INT_MAX,y=INT_MAX,w=-INT_MAX,h=-INT_MAX;
+    for(OurLayer* l=Our->Layers.pFirst;l;l=l->Item.pNext){
+        our_LayerEnsureImageBuffer(l,1);
+        if(Our->ImageX<x) x=Our->ImageX; if(Our->ImageY<y) y=Our->ImageY;
+        if(Our->ImageW>w) w=Our->ImageW; if(Our->ImageH>h) h=Our->ImageH;
+    }
+    if(w<0||h<0) return 0;
+    Our->ImageX=x; Our->ImageY=y; Our->ImageW=w; Our->ImageH=h;
+    if(Our->ImageBuffer) free(Our->ImageBuffer);
+    Our->ImageBuffer = calloc(Our->ImageW*4,Our->ImageH*sizeof(uint16_t));
+    return 1;
+}
+void our_CanvasFillImageBufferBackground(){
+    int count=Our->ImageW*Our->ImageH;
+    Our->BColorU16[0]=Our->BackgroundColor[0]*65535; Our->BColorU16[1]=Our->BackgroundColor[1]*65535;
+    Our->BColorU16[2]=Our->BackgroundColor[2]*65535; Our->BColorU16[3]=65535;
+    for(int i=0;i<count;i++){
+        uint16_t* p=&Our->ImageBuffer[i*4]; tnsVectorSet4v(p,Our->BColorU16);
+    }
+}
+void our_LayerToImageBuffer(OurLayer* ol, int composite){
     for(int row=0;row<OUR_TEX_TILES_PER_ROW;row++){ if(!ol->TexTiles[row]) continue;
         for(int col=0;col<OUR_TEX_TILES_PER_ROW;col++){ if(!ol->TexTiles[row][col]) continue;
             int sx=((real)col-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE,sy=((real)row-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE;
-            our_TileTextureToImage(ol->TexTiles[row][col], sx-Our->ImageX, sy-Our->ImageY);
+            our_TileTextureToImage(ol->TexTiles[row][col], sx-Our->ImageX, sy-Our->ImageY, composite);
         }
     }
 }
@@ -440,18 +478,31 @@ void our_LayerToTexture(OurLayer* ol){
         }
     }
 }
+void our_GetFinalDimension(int UseFrame, int* x, int* y, int* w, int* h){
+    if(UseFrame){ *x=Our->X; *y=Our->Y; *w=Our->W; *h=Our->H; }
+    else{ *x=Our->ImageX; *y=Our->ImageY; *w=Our->ImageW; *h=Our->ImageH; }
+    printf("%d %d %d %d, %d %d %d %d\n",Our->X, Our->Y, Our->W, Our->H,Our->ImageX, Our->ImageY, Our->ImageW, Our->ImageH);
+}
+uint16_t* our_GetFinalRow(int UseFrame, int row, int x, int y, int w, int h, uint16_t* temp){
+    if(!UseFrame) return &Our->ImageBuffer[Our->ImageW*(Our->ImageH-row-1)*4];
+    int userow=(h-row-1)-(Our->ImageY-(y-h));
+    if(userow<0 || userow>=Our->ImageH){ for(int i=0;i<w;i++){ tnsVectorSet4v(&temp[i*4],Our->BColorU16); }  return temp; }
+    int sstart=x>Our->ImageX?x-Our->ImageX:0, tstart=x>Our->ImageX?0:Our->ImageX-x;
+    int slen=(x+w>Our->ImageX+Our->ImageW)?(Our->ImageW-sstart):(Our->ImageW-sstart-(Our->ImageX+Our->ImageW-x-w));
+    for(int i=0;i<sstart;i++){ tnsVectorSet4v(&temp[i*4],Our->BColorU16); }
+    for(int i=sstart+slen;i<w;i++){ tnsVectorSet4v(&temp[i*4],Our->BColorU16); }
+    memcpy(&temp[tstart*4],&Our->ImageBuffer[(Our->ImageW*(userow)+sstart)*4],slen*sizeof(uint16_t)*4);
+    return temp;
+}
 static void _our_png_write(png_structp png_ptr, png_bytep data, png_size_t length){
     OurLayerWrite* LayerWrite=png_get_io_ptr(png_ptr);
     arrEnsureLength(&LayerWrite->data,LayerWrite->NextData+length,&LayerWrite->MaxData,sizeof(unsigned char));
     memcpy(&LayerWrite->data[LayerWrite->NextData], data, length);
     LayerWrite->NextData+=length;
 }
-int our_LayerExportPNG(OurLayer* l, FILE* fp, int WriteToBuffer, void** buf, int* sizeof_buf){
-    if(!l||(!fp&&!WriteToBuffer)) return 0;
-
-    if(!our_LayerEnsureImageBuffer(l, 0)) return 0;
-
-    our_LayerToImageBuffer(l);
+int our_ImageExportPNG(FILE* fp, int WriteToBuffer, void** buf, int* sizeof_buf, int UseFrame){
+    if((!fp)&&(!WriteToBuffer)) return 0;
+    if(!Our->ImageBuffer) return 0;
 
     png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0);
     png_infop info_ptr = png_create_info_struct(png_ptr);
@@ -464,8 +515,10 @@ int our_LayerExportPNG(OurLayer* l, FILE* fp, int WriteToBuffer, void** buf, int
     }else{
         png_init_io(png_ptr, fp);
     }
+
+    int X,Y,W,H; our_GetFinalDimension(UseFrame, &X,&Y,&W,&H);
     
-    png_set_IHDR(png_ptr, info_ptr,Our->ImageW,Our->ImageH,16,PNG_COLOR_TYPE_RGBA,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE,PNG_FILTER_TYPE_BASE);
+    png_set_IHDR(png_ptr, info_ptr,W,H,16,PNG_COLOR_TYPE_RGBA,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE,PNG_FILTER_TYPE_BASE);
     // Should not set gamma, we should set either srgb chunk or iccp. Gimp bug: https://gitlab.gnome.org/GNOME/gimp/-/issues/5363
     // But we still include a gamma 1.0 for convenience in OurPaint internal layer reading.
     //png_set_gAMA(png_ptr,info_ptr,0.45455);
@@ -478,8 +531,11 @@ int our_LayerExportPNG(OurLayer* l, FILE* fp, int WriteToBuffer, void** buf, int
     png_write_info(png_ptr, info_ptr);
     png_set_swap(png_ptr);
 
-    for(int i=0;i<Our->ImageH;i++){
-        png_write_row(png_ptr, (png_const_bytep)&Our->ImageBuffer[Our->ImageW*(Our->ImageH-i-1)*4]);
+    uint16_t* temp_row=calloc(W,sizeof(uint16_t)*4);
+
+    for(int i=0;i<H;i++){
+        uint16_t* final=our_GetFinalRow(UseFrame,i,X,Y,W,H,temp_row);
+        png_write_row(png_ptr, (png_const_bytep)final);
     }
 
     png_write_end(png_ptr, info_ptr);
@@ -795,9 +851,11 @@ int ourmod_ExportLayer(laOperator* a, laEvent* e){
     OurLayer* ol=a->This?a->This->EndInstance:0; if(!ol) ol=Our->CurrentLayer; if(!ol) return LA_FINISHED;
     if (a->ConfirmData){
         if (a->ConfirmData->StrData){
+            if(!our_LayerEnsureImageBuffer(ol, 0)) return LA_FINISHED;
             FILE* fp=fopen(a->ConfirmData->StrData,"wb");
             if(!fp) return LA_FINISHED;
-            our_LayerExportPNG(Our->CurrentLayer, fp, 0, 0, 0);
+            our_LayerToImageBuffer(ol, 0);
+            our_ImageExportPNG(fp, 0, 0, 0, 0);
             fclose(fp);
         }
         return LA_FINISHED;
@@ -823,22 +881,45 @@ int ourmod_ImportLayer(laOperator* a, laEvent* e){
     }
     return LA_RUNNING;
 }
+int ourinv_ExportImage(laOperator* a, laEvent* e){
+    OurLayer* ol=a->This?a->This->EndInstance:0; if(!ol) ol=Our->CurrentLayer; if(!ol) return LA_FINISHED;
+    laInvoke(a, "LA_file_dialog", e, 0, 0, 0);
+    return LA_RUNNING;
+}
+int ourmod_ExportImage(laOperator* a, laEvent* e){
+    OurLayer* ol=a->This?a->This->EndInstance:0; if(!ol) ol=Our->CurrentLayer; if(!ol) return LA_FINISHED;
+    if (a->ConfirmData){
+        if (a->ConfirmData->StrData){
+            if(!our_CanvasEnsureImageBuffer()) return LA_FINISHED;
+            FILE* fp=fopen(a->ConfirmData->StrData,"wb");
+            if(!fp) return LA_FINISHED;
+            our_CanvasFillImageBufferBackground();
+            for(OurLayer* l=Our->Layers.pLast;l;l=l->Item.pPrev){
+                our_LayerToImageBuffer(ol, 1);
+            }
+            our_ImageExportPNG(fp, 0, 0, 0, Our->ShowBorder);
+            fclose(fp);
+        }
+        return LA_FINISHED;
+    }
+    return LA_RUNNING;
+}
 
 
 int ourinv_NewBrush(laOperator* a, laEvent* e){
-    our_NewBrush("Our Brush",15,0.95,9,0.5,0.5,5,0,0,0,0); laNotifyUsers("our.brushes");
+    our_NewBrush("Our Brush",15,0.95,9,0.5,0.5,5,0,0,0,0); laNotifyUsers("our.tools.brushes");
     return LA_FINISHED;
 }
 int ourinv_RemoveBrush(laOperator* a, laEvent* e){
     OurBrush* b=a->This?a->This->EndInstance:0; if(!b) return LA_CANCELED;
-    our_RemoveLayer(b); laNotifyUsers("our.brushes");
+    our_RemoveLayer(b); laNotifyUsers("our.tools.brushes");
     return LA_FINISHED;
 }
 int ourinv_MoveBrush(laOperator* a, laEvent* e){
     OurBrush* b=a->This?a->This->EndInstance:0; if(!b) return LA_CANCELED;
     char* direction=strGetArgumentString(a->ExtraInstructionsP,"direction");
-    if(strSame(direction,"up")&&b->Item.pPrev){ lstMoveUp(&Our->Brushes, b); laNotifyUsers("our.brushes"); }
-    elif(b->Item.pNext){ lstMoveDown(&Our->Brushes, b); laNotifyUsers("our.brushes"); }
+    if(strSame(direction,"up")&&b->Item.pPrev){ lstMoveUp(&Our->Brushes, b); laNotifyUsers("our.tools.brushes"); }
+    elif(b->Item.pNext){ lstMoveDown(&Our->Brushes, b); laNotifyUsers("our.tools.brushes"); }
     return LA_FINISHED;
 }
 
@@ -860,9 +941,9 @@ int ourmod_Paint(laOperator* a, laEvent* e){
         int tl,tr,tu,tb;
         if(our_PaintGetDabs(ob,l,ex->CanvasLastX,ex->CanvasLastY,x,y,ex->LastPressure,e->Pressure,&tl,&tr,&tu,&tb)){
             our_PaintDoDabsWithSmudgeSegments(l,tl,tr,tu,tb);
+            laNotifyUsers("our.canvas"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst);
         }
         ex->CanvasLastX=x;ex->CanvasLastY=y;ex->LastPressure=e->Pressure;
-        laNotifyUsers("our.canvas");
     }
 
     return LA_RUNNING;
@@ -874,7 +955,7 @@ int ourmod_Crop(laOperator* a, laEvent* e){
     if(e->Type==LA_MOUSEMOVE||e->Type==LA_L_MOUSE_DOWN){
         real x,y; our_UiToCanvas(&ex->Base,e,&x,&y);
         our_DoCropping(ex,x,y);
-        laNotifyUsers("our.canvas");
+        laNotifyUsers("our.canvas"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst);
     }
 
     return LA_RUNNING;
@@ -910,6 +991,9 @@ int ourmod_PickColor(laOperator* a, laEvent* e){
 }
 
 
+void ourget_CanvasIdentifier(void* unused, char* buf, char** ptr){
+    *ptr="Main canvas";
+}
 void* ourget_FirstLayer(void* unused, void* unused1){
     return Our->Layers.pFirst;
 }
@@ -927,7 +1011,9 @@ void ourset_LayerTileStart(OurLayer* l, int* xy){
 }
 void* ourget_LayerImage(OurLayer* l, int* r_size, int* r_is_copy){
     void* buf=0;
-    if(our_LayerExportPNG(l,0,1,&buf,r_size)){ *r_is_copy=1; return buf; }
+    if(!our_LayerEnsureImageBuffer(l, 0)){ *r_is_copy=0; return 0; }
+    our_LayerToImageBuffer(l, 0);
+    if(our_ImageExportPNG(0,1,&buf,r_size, 0)){ *r_is_copy=1; return buf; }
     *r_is_copy=0; return buf;
 }
 void ourset_LayerImage(OurLayer* l, void* data, int size){
@@ -939,8 +1025,8 @@ void ourset_LayerMove(OurLayer* l, int move){
     elif(move>0 && l->Item.pNext){ lstMoveDown(&Our->Layers, l); laNotifyUsers("our.canvas.layers"); }
 }
 void ourset_BrushMove(OurBrush* b, int move){
-    if(move<0 && b->Item.pPrev){ lstMoveUp(&Our->Brushes, b); laNotifyUsers("our.brushes"); }
-    elif(move>0 && b->Item.pNext){ lstMoveDown(&Our->Brushes, b); laNotifyUsers("our.brushes"); }
+    if(move<0 && b->Item.pPrev){ lstMoveUp(&Our->Brushes, b); laNotifyUsers("our.tools.brushes"); }
+    elif(move>0 && b->Item.pNext){ lstMoveDown(&Our->Brushes, b); laNotifyUsers("our.tools.brushes"); }
 }
 void ourset_BackgroundColor(void* unused, real* arr){
     memcpy(Our->BackgroundColor, arr, sizeof(real)*3); laNotifyUsers("our.canvas");
@@ -966,6 +1052,11 @@ void ourset_LayoutPosition(OurLayer* l, int* xy){
 void ourreset_Canvas(OurPaint* op){
     while(op->Layers.pFirst){ our_RemoveLayer(op->Layers.pFirst); }
 }
+void ourpropagate_Tools(OurPaint* p, laUDF* udf, int force){
+    for(OurBrush* b=p->Brushes.pFirst;b;b=b->Item.pNext){
+        if(force || !laget_InstanceActiveUDF(b)){ laset_InstanceUDF(b, udf); }
+    }
+}
 
 #define OUR_ADD_PRESSURE_SWITCH(p)\
     laAddEnumItemAs(p,"NONE","None","Not using pressure",0,0);\
@@ -976,6 +1067,8 @@ void ourui_MenuButtons(laUiList *uil, laPropPack *pp, laPropPack *actinst, laCol
     muil = laMakeMenuPage(uil, c, "File");{
         mc = laFirstColumn(muil);
         laShowLabel(muil, mc, "Our Paint", 0, 0);
+        laShowItem(muil, mc, 0, "OUR_export_image");
+        laShowSeparator(muil,mc);
         laShowItem(muil, mc, 0, "OUR_export_layer");
         laShowItem(muil, mc, 0, "OUR_import_layer");
         laui_DefaultMenuButtonsFileEntries(muil,pp,actinst,extracol,0);
@@ -998,6 +1091,7 @@ void ourRegisterEverything(){
     laCreateOperatorType("OUR_move_brush","Move Brush","Remove this brush",0,0,0,ourinv_MoveBrush,0,0,0);
     laCreateOperatorType("OUR_action","Action","Doing action on a layer",0,0,0,ourinv_Action,ourmod_Action,0,LA_EXTRA_TO_PANEL);
     laCreateOperatorType("OUR_pick","Pick color","Pick color on the widget",0,0,0,ourinv_PickColor,ourmod_PickColor,0,LA_EXTRA_TO_PANEL);
+    laCreateOperatorType("OUR_export_image","Export Image","Export the image",0,0,0,ourinv_ExportImage,ourmod_ExportImage,L'🖼',0);
 
     laRegisterUiTemplate("panel_canvas", "Canvas", ourui_CanvasPanel, 0, 0,"Our Paint");
     laRegisterUiTemplate("panel_layers", "Layers", ourui_LayersPanel, 0, 0,0);
@@ -1009,8 +1103,7 @@ void ourRegisterEverything(){
 
     pc=laAddPropertyContainer("our_paint","Our Paint","OurPaint main",0,0,sizeof(OurPaint),0,0,1);
     laAddSubGroup(pc,"canvas","Canvas","OurPaint canvas","our_canvas",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
-    laAddSubGroup(pc,"brushes","Brushes","Brushes","our_brush",0,0,ourui_Brush,offsetof(OurPaint,CurrentBrush),0,0,0,0,0,0,offsetof(OurPaint,Brushes),0);
-    laAddSubGroup(pc,"current_brush","Current Brush","Current brush","our_brush",0,0,0,offsetof(OurPaint,CurrentBrush),ourget_FirstBrush,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);
+    laAddSubGroup(pc,"tools","Tools","OurPaint tools","our_tools",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
     laAddFloatProperty(pc,"current_color","Current Color","Current color used to paint",0,0,0,1,0,0.05,0.8,0,offsetof(OurPaint,CurrentColor),0,0,3,0,0,0,0,0,0,0,LA_PROP_IS_LINEAR_SRGB);
     laAddFloatProperty(pc,"background_color","Background Color","Background color of the canvas",0,0,0,1,0,0.05,0.8,0,offsetof(OurPaint,BackgroundColor),0,0,3,0,0,0,0,ourset_BackgroundColor,0,0,LA_PROP_IS_LINEAR_SRGB);
     laAddFloatProperty(pc,"border_alpha","Border Alpha","Alpha of the border region around the canvas",0,0,0,1,0,0.05,0.5,0,offsetof(OurPaint,BorderAlpha),0,0,0,0,0,0,0,ourset_BorderAlpha,0,0,0);
@@ -1020,6 +1113,12 @@ void ourRegisterEverything(){
     p=laAddEnumProperty(pc,"show_border","Show Border","Whether to show border on the canvas",0,0,0,0,0,offsetof(OurPaint,ShowBorder),0,ourset_ShowBorder,0,0,0,0,0,0,0,0);
     laAddEnumItemAs(p,"FALSE","No","Dont' show border on the canvas",OUR_TOOL_PAINT,L'🖌');
     laAddEnumItemAs(p,"TRUE","Yes","Show border on the canvas",OUR_TOOL_CROP,L'🖼');
+
+
+    pc=laAddPropertyContainer("our_tools","Our Tools","OurPaint tools",0,0,sizeof(OurPaint),0,0,1);
+    laPropContainerExtraFunctions(pc,0,0,0,ourpropagate_Tools,0);
+    laAddSubGroup(pc,"brushes","Brushes","Brushes","our_brush",0,0,ourui_Brush,offsetof(OurPaint,CurrentBrush),0,0,0,0,0,0,offsetof(OurPaint,Brushes),0);
+    laAddSubGroup(pc,"current_brush","Current Brush","Current brush","our_brush",0,0,0,offsetof(OurPaint,CurrentBrush),ourget_FirstBrush,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);
     
     pc=laAddPropertyContainer("our_brush","Our Brush","OurPaint brush",0,0,sizeof(OurBrush),0,0,2);
     laAddStringProperty(pc,"name","Name","Name of the layer",0,0,0,0,1,offsetof(OurBrush,Name),0,0,0,0,LA_AS_IDENTIFIER);
@@ -1043,12 +1142,14 @@ void ourRegisterEverything(){
 
     pc=laAddPropertyContainer("our_canvas","Our Canvas","OurPaint canvas",0,0,sizeof(OurPaint),0,0,1);
     laPropContainerExtraFunctions(pc,0,ourreset_Canvas,0,0,0);
+    Our->CanvasSaverDummyProp=laPropContainerManageable(pc, offsetof(OurPaint,CanvasSaverDummyList));
+    laAddStringProperty(pc,"identifier","Identifier","Canvas identifier placeholder",0,0,0,0,0,0,0,ourget_CanvasIdentifier,0,0,0);
     laAddSubGroup(pc,"layers","Layers","Layers","our_layer",0,0,ourui_Layer,offsetof(OurPaint,CurrentLayer),0,0,0,0,0,0,offsetof(OurPaint,Layers),0);
     laAddSubGroup(pc,"current_layer","Current Layer","Current layer","our_layer",0,0,0,offsetof(OurPaint,CurrentLayer),ourget_FirstLayer,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);
     laAddIntProperty(pc,"size","Size","Size of the cropping area",0,"X,Y","px",0,0,0,2400,0,offsetof(OurPaint,W),0,0,2,0,0,0,0,ourset_CanvasSize,0,0,0);
     laAddIntProperty(pc,"position","Position","Position of the cropping area",0,"X,Y","px",0,0,0,2400,0,offsetof(OurPaint,X),0,0,2,0,0,0,0,ourset_CanvasPosition,0,0,0);
 
-    pc=laAddPropertyContainer("our_layer","Our Layer","OurPaint layer",0,0,sizeof(OurLayer),0,0,2);
+    pc=laAddPropertyContainer("our_layer","Our Layer","OurPaint layer",0,0,sizeof(OurLayer),0,0,1);
     laPropContainerExtraFunctions(pc,ourbeforefree_Layer,ourbeforefree_Layer,0,0,0);
     laAddStringProperty(pc,"name","Name","Name of the layer",0,0,0,0,1,offsetof(OurLayer,Name),0,0,0,0,LA_AS_IDENTIFIER);
     laAddIntProperty(pc,"__move","Move Slider","Move Slider",LA_WIDGET_HEIGHT_ADJUSTER,0,0,0,0,0,0,0,0,0,ourset_LayerMove,0,0,0,0,0,0,0,0,0);
@@ -1070,7 +1171,10 @@ void ourRegisterEverything(){
 
     laSetMenuBarTemplates(ourui_MenuButtons, laui_DefaultMenuExtras, "OurPaint v0.1");
 
-    laSaveProp("our");
+    laSaveProp("our.canvas");
+    laSaveProp("our.tools");
+
+    laGetSaverDummy(Our,Our->CanvasSaverDummyProp);
 }
 
 

+ 4 - 0
ourpaint.h

@@ -77,6 +77,9 @@ STRUCTURE(OurDab){
 STRUCTURE(OurPaint){
     real pad;
 
+    laListHandle CanvasSaverDummyList;
+    laProp*      CanvasSaverDummyProp;
+
     laListHandle Layers;
     OurLayer*    CurrentLayer;
     laListHandle Brushes;
@@ -102,6 +105,7 @@ STRUCTURE(OurPaint){
 
     real CurrentColor[3];
     real BackgroundColor[3];
+    uint16_t BColorU16[4];
     real BorderAlpha;
 
     uint16_t *ImageBuffer;