Skip to content

Commit de9ce8e

Browse files
committed
New! MarkdownComponent and CRCDemo contents.
1 parent 48e3460 commit de9ce8e

12 files changed

Lines changed: 1832 additions & 118 deletions

File tree

demo/SquarePineDemo.jucer

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
file="source/demos/EffectChainDemo.h"/>
9797
<FILE id="brHreQ" name="iCUESDKDemo.h" compile="0" resource="0" file="source/demos/iCUESDKDemo.h"/>
9898
<FILE id="vSHEQC" name="ImageDemo.h" compile="0" resource="0" file="source/demos/ImageDemo.h"/>
99+
<FILE id="uzQ1sq" name="MarkdownDemo.h" compile="0" resource="0" file="source/demos/MarkdownDemo.h"/>
99100
<FILE id="S1SGkR" name="MediaDeviceListerDemo.h" compile="0" resource="0"
100101
file="source/demos/MediaDeviceListerDemo.h"/>
101102
<FILE id="hoUe5P" name="OpenGLDetailsDemo.h" compile="0" resource="0"

demo/source/MainModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "demos/EasingsDemo.h"
2828
#include "demos/EffectChainDemo.h"
2929
#include "demos/ImageDemo.h"
30+
#include "demos/MarkdownDemo.h"
3031
#include "demos/MediaDeviceListerDemo.h"
3132
#include "demos/OpenGLDetailsDemo.h"
3233
#include "demos/ParticleSystemDemo.h"

demo/source/demos/CRCDemo.h

Lines changed: 327 additions & 58 deletions
Large diffs are not rendered by default.

demo/source/demos/MarkdownDemo.h

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
//==============================================================================
2+
/** Demo showing how to use the MarkdownComponent.
3+
4+
This demonstrates parsing and rendering markdown from both strings and files,
5+
with auto-reload functionality and customizable styling.
6+
*/
7+
class MarkdownDemo final : public DemoBase,
8+
private Button::Listener,
9+
private FileDragAndDropTarget
10+
{
11+
public:
12+
/** Constructor. */
13+
MarkdownDemo (SharedObjects& sharedObjs) :
14+
DemoBase (sharedObjs, "Markdown")
15+
{
16+
SQUAREPINE_CRASH_TRACER
17+
18+
setSize (800, 600);
19+
20+
// Create the markdown component and viewport
21+
viewport.setViewedComponent (&markdownComponent, false);
22+
viewport.setScrollBarsShown (true, false); // Vertical scrolling only
23+
addAndMakeVisible (viewport);
24+
25+
// Create demo buttons
26+
loadStringButton.setButtonText (TRANS ("Load Sample Text"));
27+
loadStringButton.addListener (this);
28+
addAndMakeVisible (loadStringButton);
29+
30+
loadFileButton.setButtonText (TRANS ("Load File..."));
31+
loadFileButton.addListener (this);
32+
addAndMakeVisible (loadFileButton);
33+
34+
autoReloadToggle.setButtonText (TRANS ("Auto-reload file"));
35+
autoReloadToggle.setToggleable (true);
36+
autoReloadToggle.addListener (this);
37+
addAndMakeVisible (autoReloadToggle);
38+
39+
fontSizeSlider.setSliderStyle (Slider::LinearHorizontal);
40+
fontSizeSlider.setRange (8.0, 24.0, 1.0);
41+
fontSizeSlider.setValue (14.0);
42+
fontSizeSlider.setTextBoxStyle (Slider::TextBoxRight, false, 50, 50);
43+
fontSizeSlider.onValueChange = [this]()
44+
{
45+
markdownComponent.setBaseFontSize ((float) fontSizeSlider.getValue());
46+
updateMarkdownSize();
47+
};
48+
49+
addAndMakeVisible (fontSizeSlider);
50+
51+
fontSizeLabel.setText (TRANS ("Font Size:"), dontSendNotification);
52+
fontSizeLabel.attachToComponent (&fontSizeSlider, true);
53+
addAndMakeVisible (fontSizeLabel);
54+
55+
loadSampleMarkdown();
56+
}
57+
58+
//==============================================================================
59+
/** @internal */
60+
void paint (Graphics& g) override
61+
{
62+
g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
63+
64+
// Draw drag and drop hint
65+
if (isDragOver)
66+
{
67+
g.setColour (Colours::lightblue.withAlpha (0.3f));
68+
g.fillAll();
69+
70+
g.setColour (Colours::lightblue);
71+
g.drawRect (getLocalBounds(), 2);
72+
73+
g.setFont (16.0f);
74+
g.drawText (TRANS ("Drop a markdown file here!"), getLocalBounds(), Justification::centred);
75+
}
76+
}
77+
78+
/** @internal */
79+
void resized() override
80+
{
81+
auto bounds = getLocalBounds();
82+
auto buttonArea = bounds.removeFromTop (80).reduced (10);
83+
84+
// First row of controls
85+
auto firstRow = buttonArea.removeFromTop (30);
86+
loadStringButton.setBounds (firstRow.removeFromLeft (120));
87+
firstRow.removeFromLeft (10);
88+
loadFileButton.setBounds (firstRow.removeFromLeft (120));
89+
firstRow.removeFromLeft (10);
90+
autoReloadToggle.setBounds (firstRow.removeFromLeft (120));
91+
92+
// Second row for font size
93+
buttonArea.removeFromTop (10);
94+
auto secondRow = buttonArea.removeFromTop (30);
95+
secondRow.removeFromLeft (70); // Space for label
96+
fontSizeSlider.setBounds (secondRow.removeFromLeft (200));
97+
98+
viewport.setBounds (bounds.reduced (10));
99+
updateMarkdownSize();
100+
}
101+
102+
//==============================================================================
103+
/** @internal */
104+
bool isInterestedInFileDrag (const StringArray& files) override
105+
{
106+
for (const auto& file : files)
107+
if (File (file).hasFileExtension (".md;.markdown;.txt"))
108+
return true;
109+
110+
return false;
111+
}
112+
113+
/** @internal */
114+
void fileDragEnter (const StringArray&, int, int) override
115+
{
116+
isDragOver = true;
117+
repaint();
118+
}
119+
120+
/** @internal */
121+
void fileDragExit (const StringArray&) override
122+
{
123+
isDragOver = false;
124+
repaint();
125+
}
126+
127+
/** @internal */
128+
void filesDropped (const StringArray& files, int, int) override
129+
{
130+
isDragOver = false;
131+
132+
if (const File file = files.strings.getFirst(); file.existsAsFile())
133+
{
134+
markdownComponent.setMarkdownFile (file);
135+
autoReloadToggle.setToggleState (false, dontSendNotification);
136+
updateMarkdownSize();
137+
}
138+
139+
repaint();
140+
}
141+
142+
private:
143+
//==============================================================================
144+
Viewport viewport;
145+
sp::MarkdownComponent markdownComponent;
146+
TextButton loadStringButton, loadFileButton;
147+
ToggleButton autoReloadToggle;
148+
Slider fontSizeSlider;
149+
Label fontSizeLabel;
150+
std::unique_ptr<FileChooser> fileChooser;
151+
bool isDragOver = false;
152+
153+
//==============================================================================
154+
void updateMarkdownSize()
155+
{
156+
if (viewport.getWidth() > 0)
157+
markdownComponent.setPreferredWidth (viewport.getWidth());
158+
}
159+
160+
/** @internal */
161+
void buttonClicked (Button* button) override
162+
{
163+
SQUAREPINE_CRASH_TRACER
164+
165+
if (button == &loadStringButton)
166+
{
167+
loadSampleMarkdown();
168+
}
169+
else if (button == &loadFileButton)
170+
{
171+
if (fileChooser != nullptr)
172+
return;
173+
174+
fileChooser = std::make_unique<FileChooser> (TRANS ("Choose a markdown file..."), File(), "*.md;*.markdown;*.txt");
175+
176+
fileChooser->launchAsync (FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles,
177+
[this] (const FileChooser& chooser)
178+
{
179+
if (const auto file = chooser.getResult(); file.existsAsFile())
180+
{
181+
markdownComponent.setMarkdownFile (file);
182+
autoReloadToggle.setToggleState (false, dontSendNotification);
183+
updateMarkdownSize();
184+
}
185+
});
186+
}
187+
else if (button == &autoReloadToggle)
188+
{
189+
markdownComponent.setAutoReload (autoReloadToggle.getToggleState());
190+
}
191+
}
192+
193+
void loadSampleMarkdown()
194+
{
195+
const char* const sampleMarkdown = R"(# SquarePine Markdown Demo
196+
197+
This is a demonstration of the **MarkdownComponent** for JUCE.
198+
199+
## Features
200+
201+
The component supports many markdown features:
202+
203+
- **Bold text** using double asterisks
204+
- *Italic text* using single asterisks
205+
- `Inline code` using backticks
206+
- [Links](https://www.squarepine.io) with clickable URLs
207+
- Headers at multiple levels (from H1, H2, H3, H4, H5, and maximum H6)
208+
- Unordered lists like this one
209+
- Ordered lists (see below)
210+
- Code blocks with syntax highlighting
211+
212+
### Images
213+
214+
The component supports both raster and vector images:
215+
216+
![Sample Image]({SAMPLE_SVG} 300x150)
217+
218+
*Example: Sample image demonstrating web URL loading*
219+
220+
You can also specify size constraints:
221+
- `![alt text]({SAMPLE_PNG})` - Original size
222+
- `![alt text]({SAMPLE_PNG} 300)` - Max width 300px
223+
- `![alt text]({SAMPLE_PNG} x200)` - Max height 200px
224+
- `![alt text]({SAMPLE_PNG} 300x200)` - Max 300x200px
225+
226+
**Local Images**: When loading from files, images are resolved relative to the markdown file's directory.
227+
228+
### Code Example
229+
230+
Here's some C++ code showing how to use the component:
231+
232+
```cpp
233+
// Create and configure a MarkdownComponent
234+
sp::MarkdownComponent markdown;
235+
markdown.setMarkdownText ("# Hello World\n\nThis is **bold** text.");
236+
markdown.setBaseFontSize (16.0f);
237+
markdown.setAutoReload (true);
238+
239+
// Add to your component
240+
addAndMakeVisible (markdown);
241+
```
242+
243+
## Usage Instructions
244+
245+
1. **Load Sample Text**: Click to see this demo content
246+
2. **Load File**: Browse for a `.md`, `.markdown`, or `.txt` file
247+
3. **Auto-reload**: Enable to automatically reload files when they change
248+
4. **Font Size**: Adjust the base font size with the slider
249+
5. **Drag & Drop**: Drop markdown files directly onto this demo
250+
251+
### Customisation Options
252+
253+
The `MarkdownComponent` provides several customisation methods:
254+
255+
- `setBaseFontSize()` - Adjust the base font size
256+
- `setColours()` - Customize text, heading, code, and link colors
257+
- `setAutoReload()` - Enable/disable file change monitoring
258+
- `setMarkdownText()` - Set content from a string
259+
- `setMarkdownFile()` - Load content from a file
260+
261+
### Supported Markdown Syntax
262+
263+
| Element | Syntax | Example |
264+
|---------|--------|---------|
265+
| Headers | `# ## ###` | # Heading 1 |
266+
| Bold | `**text**` | **bold text** |
267+
| Italic | `*text*` | *italic text* |
268+
| Code | `` `text` `` | `inline code` |
269+
| Links | `[text](url)` | [SquarePine](https://squarepine.io) |
270+
| Images | `![alt]({SAMPLE_PNG})` | ![Demo]({SAMPLE_PNG} 100x50) |
271+
| Lists | `- item` or `1. item` | • Bullet or 1. Numbered |
272+
273+
That's it! The component handles parsing and rendering automatically with proper JUCE integration.
274+
275+
---
276+
277+
*Try dragging a markdown file onto this demo to see it in action!*
278+
)";
279+
280+
auto sm = String::fromUTF8 (sampleMarkdown)
281+
.replace ("{SAMPLE_SVG}", "https://raw.githubusercontent.com/SquarePine/squarepine_core/main/demo/assets/logos/squarepine_logo_colour.svg")
282+
.replace ("{SAMPLE_PNG}", "https://raw.githubusercontent.com/SquarePine/squarepine_core/main/demo/assets/logos/squarepine_icon_32.png");
283+
284+
markdownComponent.setMarkdownText (sm);
285+
autoReloadToggle.setToggleState (false, dontSendNotification);
286+
updateMarkdownSize();
287+
}
288+
289+
//==============================================================================
290+
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MarkdownDemo)
291+
};

demo/source/main/MainComponent.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ MainComponent::MainComponent (SharedObjects& sharedObjs) :
2525
demos.add (comp);
2626
};
2727

28+
addDemo (new MarkdownDemo (sharedObjs));
2829
addDemo (new CRCDemo (sharedObjs));
2930
addDemo (new EaseListComponent (sharedObjs));
3031
addDemo (new ImageDemo (sharedObjs));

0 commit comments

Comments
 (0)