# Whiteboard

> मुक्त हस्त-चित्रण सतह, चिकने स्ट्रोक, कॉन्फ़िगर करने योग्य रंग और मोटाई के साथ।

Source: https://crossfly.dev/hi/docs/ui/widgets/whiteboard — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Whiteboard

`Whiteboard` एक **मुक्त चित्रण** सतह है: उपयोगकर्ता अपनी उंगली/पॉइंटर खींचता है और घटक बिंदुओं को दर्ज करता है, स्ट्रोक को चिकना करता है (पड़ोसियों का भारित औसत) और उसे एक आंतरिक `Image` पर रेंडर करता है। यह हस्ताक्षर कैप्चर, हस्त-टिप्पणियों और छोटे रेखाचित्रों का आधार है। प्रत्येक पूर्ण स्ट्रोक (`onTouchUp` पर) छवि में "जला दिया" जाता है, ताकि इतिहास हर फ़्रेम पर सभी बिंदुओं को पुनः संसाधित किए बिना संचित हो।

आप पेन के रंग (`setPenColor`), मोटाई (`thick` फ़ील्ड) को नियंत्रित करते हैं और साफ़ कर सकते हैं (`clear()`) या पृष्ठभूमि छवि को निर्यात/परिभाषित कर सकते हैं (`getImage`/`setImage`)।

> 🟢 · **पैकेज:** `dev.crossfly.ui` · **विस्तार करता है:** `Component` · **स्टाइल:** `ComponentStyle` (डिफ़ॉल्ट रूप से सफ़ेद पृष्ठभूमि)

## कब उपयोग करें
- एक हस्ताक्षर या मुक्त हस्त-चित्र कैप्चर करना।
- किसी मौजूदा छवि पर टिप्पणी करना (उसे `setImage` के माध्यम से पास करें)।

## कब उपयोग न करें
- संरचित डेटा प्रदर्शित/प्लॉट करना → [`chartview`](/docs/ui/widgets/chartview) का उपयोग करें।

## दिखावट
घटक के आकार की सफ़ेद पृष्ठभूमि (`backColor`)। स्ट्रोक चिकनी रेखाएँ हैं जिनकी मोटाई `Styles.fontHeight/3` (मोटा) या `Styles.fontHeight/10` (पतला) होती है, पेन के रंग में (अल्फा को अपारदर्शी के लिए बाध्य किया गया)। घटक में `hasPan(true)` है, यानी यह चित्र बनाने के लिए खींचने के इशारे को कैप्चर करता है।

## पूर्ण उदाहरण (कॉपी करें, पेस्ट करें और चलाएँ)
`Whiteboard` एक सामान्य घटक है: यह शरीर को घेरने के लिए `add(LAY_FILL, ...)` के साथ सीधे स्क्रीन में जाता है। यह उदाहरण बुनियादी उपयोग (नीला पेन, मोटा स्ट्रोक) का पुनः उपयोग करता है और साफ़ करने के लिए एक बटन जोड़ता है।

```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

/** चलाने योग्य मुख्य स्क्रीन। launcher (classname) की ओर संकेत करें और चलाएँ: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Whiteboard board = new Whiteboard();
      board.setPenColor(0x0000FF);   // नीला (ड्रॉइंग में alpha को अपारदर्शी पर बाध्य किया जाता है)
      board.thick = true;            // मोटी लकीर

      Button limpar = new Button("Limpar")
         .onAction(c -> board.clear());
      add(LAY_AUTO, limpar);

      add(LAY_FILL, board);          // स्क्रीन का मुख्य भाग घेरता है
   }
}
```

> नीचे दिए गए अंश **केवल मुख्य भाग** दिखाते हैं (जो `onShow()` के अंदर जाता है)। चलाने के लिए, उन्हें ऊपर दिए गए `MainWindow` ढाँचे में रखें।

## बुनियादी उपयोग
```java
Whiteboard board = new Whiteboard();
board.setPenColor(0x0000FF);   // नीला (ड्रॉइंग में alpha को अपारदर्शी पर बाध्य किया जाता है)
board.thick = true;            // मोटी लकीर
container.add(LAY_FILL, board);

// कहीं और, साफ़ करने के लिए एक बटन:
btnLimpar.onAction(c -> board.clear());
```

## कंस्ट्रक्टर
| कंस्ट्रक्टर | विवरण |
|---|---|
| `Whiteboard()` | सफ़ेद पृष्ठभूमि और `hasPan(true)` के साथ सतह बनाता है (चित्रण के लिए तैयार)। |

## गुण और अनुकूलन
| गुण / मेथड | प्रकार | डिफ़ॉल्ट | क्या करता है |
|---|---|---|---|
| `setPenColor(int)` | `void` | `BLACK` | पेन का रंग परिभाषित करता है (चित्रण अल्फा को अपारदर्शी बाध्य करता है)। |
| `getPenColor()` | `int` | — | पेन का वर्तमान रंग लौटाता है। |
| `thick` | `boolean` (फ़ील्ड) | `false` | `true` = मोटा स्ट्रोक (`fontHeight/3`); `false` = पतला (`fontHeight/10`)। |
| `clear()` | `void` | — | छवि और संचित बिंदुओं को साफ़ करता है। |
| `getImage()` | `Image` | `null` | चित्रण छवि लौटाता है (यदि कुछ नहीं बनाया गया तो `null` हो सकता है)। |
| `setImage(Image)` | `void` | — | पृष्ठभूमि/आधार छवि परिभाषित करता है (खाली सतह के लिए `null` पास करें)। `throws ImageException`। |
| `Whiteboard.debugPoints` | `boolean` स्थैतिक | `false` | डिबगिंग: बिंदुओं की गिनती/रेंडरिंग समय प्रदर्शित करता है। |

## कॉलबैक और इवेंट
`Whiteboard` इशारों को आंतरिक रूप से संभालता है; यह "स्ट्रोक पूर्ण" का कोई कॉलबैक उजागर नहीं करता।

| इवेंट (आंतरिक) | व्यवहार |
|---|---|
| `onTouchDown(x,y,button)` | एक नया स्ट्रोक शुरू करता है और पहला बिंदु दर्ज करता है। |
| `onPan(x,y,dx,dy)` | उपयोगकर्ता के खींचने के दौरान बिंदुओं को संचित करता है और पुनः रंगता है। |
| `onTouchUp(x,y,button)` | स्ट्रोक को अंतिम रूप देता है और चित्रण को आंतरिक `Image` में "जला देता है"। |

## स्थितियाँ
- **चित्रण करते हुए**: `onTouchDown` और `onTouchUp` के बीच, बिंदु एक अस्थायी बफ़र में रहते हैं और प्रत्येक `onPan` पर चिकने/रेंडर किए जाते हैं।
- **समेकित**: `onTouchUp` में, स्ट्रोक `Image` में दर्ज होता है और बफ़र साफ़ हो जाता है (प्रति फ़्रेम लागत स्ट्रोक की कुल संख्या के साथ नहीं बढ़ती)।

### रंग चयन और निर्यात के साथ हस्ताक्षर पैनल
```java
Whiteboard assinatura = new Whiteboard();
assinatura.thick = false;                 // हस्ताक्षर के लिए पतला स्ट्रोक
container.add(LAY_FILL, assinatura);

btnPreto.onAction(c -> assinatura.setPenColor(0x000000));
btnAzul.onAction (c -> assinatura.setPenColor(0x0000FF));
btnLimpar.onAction(c -> assinatura.clear());

// पुष्टि पर, परिणामी इमेज पुनः प्राप्त करें:
btnOk.onAction(c -> {
   Image desenho = assinatura.getImage();   // अगर कुछ नहीं बनाया गया तो null हो सकता है
   if (desenho != null)
      salvarAssinatura(desenho);
});
```

## अच्छी प्रथाएँ
- हस्ताक्षर के लिए `thick = false` (अधिक सटीक स्ट्रोक) और व्यापक रेखाचित्रों के लिए `thick = true` पसंद करें।
- निर्यात से पहले हमेशा `getImage() != null` जाँचें: यदि उपयोगकर्ता ने कुछ नहीं बनाया, तो छवि अभी भी `null` है।
- एक `clear()` बटन प्रदान करें — प्रति स्ट्रोक कोई "पूर्ववत करें" नहीं है।

## आम गलतियाँ
- पारदर्शिता की अपेक्षा में स्पष्ट अल्फा वाला रंग पास करना: चित्रण **अल्फा को अपारदर्शी बाध्य करता है** (`0xFF000000 | cor`)।
- स्ट्रोक कॉलबैक की अपेक्षा करना: इंटरैक्शन के बाद मेथड (`getImage`) का उपयोग करें; स्ट्रोक पूर्णता का कोई `onAction` नहीं है।

## यह भी देखें
- क्षेत्र गाइड: [`ui/`](/docs/ui) · रेसिपी: [`cookbook/`](/docs/cookbook)
- अवधारणा (छवियाँ, ग्राफिक प्रिमिटिव): [`concepts/`](/docs/concepts)
- संबंधित घटक: [`chartview`](/docs/ui/widgets/chartview)
