Skip to content

Commit

Permalink
feat: group shapes under one toolbar icon
Browse files Browse the repository at this point in the history
(progress towards new toolbar)
  • Loading branch information
dominiksta committed Sep 19, 2024
1 parent 0fc3f38 commit 6a5aaa9
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 29 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ Changelog
- When wournal is minimized and a file is opened, the window was not
automatically unminimized.

### Changed

- Shapes (ruler, rectangle & ellipse) are now grouped under a single toolbar
entry.

`0.0.8` - _2024-08-30_
----------------------------------------------------------------------
**Tabs!**
Expand Down
169 changes: 142 additions & 27 deletions src/renderer/app/toolbars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { CanvasToolEraser } from "document/CanvasToolEraser";
import { CanvasToolPen } from "document/CanvasToolPen";
import { CanvasToolText } from "document/CanvasToolText";
import { Newable } from "util/Newable";
import { CanvasTool } from "document/CanvasTool";
import { CanvasTool, CanvasToolName, CanvasToolNames } from "document/CanvasTool";
import Toolbar, { ToolbarSeperator } from "common/toolbar";
import { ToolbarButton } from "common/toolbar";
import { CanvasToolRectangle } from "document/CanvasToolRectangle";
Expand Down Expand Up @@ -38,11 +38,6 @@ export default class Toolbars extends Component {
const d = this.props.doc;
const configCtx = this.getContext(ConfigCtx);

const noSelection = d.pipe(
rx.switchMap(doc => doc.selection.available),
rx.map(v => !v)
);

const isSinglePage = d.derive(d => d.isSinglePage);

const currentTool = d.pipe(rx.switchMap(doc => doc.currentTool));
Expand Down Expand Up @@ -83,6 +78,16 @@ export default class Toolbars extends Component {
const windowList =
new rx.State<{ title: string, id: number, focused: boolean }[]>([]);

const shapeTools = [
'CanvasToolRuler', 'CanvasToolRectangle', 'CanvasToolEllipse'
] as const;
const lastShapeTool = new rx.State<typeof shapeTools[number]>('CanvasToolRuler');
this.subscribe(currentTool, tool => {
const t = tool.name as typeof shapeTools[number];
if (shapeTools.includes(t)) lastShapeTool.next(t);
});
const shapePopoverRef = this.ref<ui5.types.Popover>();

return [
h.div({ fields: { className: 'topbar' } }, [
// menu
Expand Down Expand Up @@ -619,28 +624,27 @@ export default class Toolbars extends Component {
events: { click: _ => api.setTool('CanvasToolImage') }
}),
ToolbarButton.t({
fields: { id: 'btn-tools-shapes' },
props: {
img: 'icon:draw-rectangle',
alt: `Rectangle (${globalCmnds['tool_rectangle'].shortcut})`,
current: isCurrentTool(CanvasToolRectangle),
},
events: { click: _ => api.setTool('CanvasToolRectangle') }
}),
ToolbarButton.t({
props: {
img: 'icon:tnt/unit',
alt: `Ruler (${globalCmnds['tool_ruler'].shortcut})`,
current: isCurrentTool(CanvasToolRuler),
},
events: { click: _ => api.setTool('CanvasToolRuler') }
}),
ToolbarButton.t({
props: {
img: 'icon:circle-task',
alt: `Ruler (${globalCmnds['tool_ellipse'].shortcut})`,
current: isCurrentTool(CanvasToolEllipse),
img: lastShapeTool.derive(lt => {
return ({
'CanvasToolRuler': 'icon:tnt/unit',
'CanvasToolRectangle': 'icon:draw-rectangle',
'CanvasToolEllipse': 'icon:circle-task',
})[lt]
}),
alt: `Shapes`,
current: currentTool.map(ct => shapeTools.includes(ct.name as any)),
},
events: { click: _ => api.setTool('CanvasToolEllipse') }
events: {
click: _ => {
if (shapeTools.includes(d.value.currentTool.value.name as any)) {
shapePopoverRef.current.open = !shapePopoverRef.current.open;
} else {
api.setTool(lastShapeTool.value);
}
}
}
}),
ToolbarButton.t({
props: {
Expand Down Expand Up @@ -727,6 +731,56 @@ export default class Toolbars extends Component {
)),
]),

]),

ui5.popover({
ref: shapePopoverRef,
id: 'popover-shape',
fields: {
headerText: 'Shapes', opener: 'btn-tools-shapes',
placementType: 'Bottom',
initialFocus: lastShapeTool.derive(lt => `choice-${lt}`),
},
style: { marginTop: '1em' },
}, [
ToolTypeChoice.t({
fields: { id: 'choice-CanvasToolRuler' },
props: {
icon: 'tnt/unit', name: `Ruler`,
additionalText: globalCmnds['tool_ruler'].shortcut,
active: lastShapeTool.derive(lt => lt === 'CanvasToolRuler'),
},
events: { click: _ => {
api.setTool('CanvasToolRuler');
shapePopoverRef.current.open = false;
}},
}),
ToolTypeChoice.t({
fields: { id: 'choice-CanvasToolRectangle' },
props: {
icon: 'draw-rectangle',
name: `Rectangle`,
additionalText: globalCmnds['tool_rectangle'].shortcut,
active: lastShapeTool.derive(lt => lt === 'CanvasToolRectangle'),
},
events: { click: _ => {
api.setTool('CanvasToolRectangle');
shapePopoverRef.current.open = false;
}},
}),
ToolTypeChoice.t({
fields: { id: 'choice-CanvasToolEllipse' },
props: {
icon: 'circle-task',
name: `Ellipse`,
additionalText: globalCmnds['tool_ellipse'].shortcut,
active: lastShapeTool.derive(lt => lt === 'CanvasToolEllipse'),
},
events: { click: _ => {
api.setTool('CanvasToolEllipse');
shapePopoverRef.current.open = false;
}},
}),
])
]
}
Expand All @@ -736,6 +790,67 @@ export default class Toolbars extends Component {
width: '100%',
zIndex: '2',
outline: 'none',
}
},
'#popover-shape > *': {
display: 'flex',
},
})
}


@Component.register
class ToolTypeChoice extends Component<{
events: { click: MouseEvent }
}> {
props = {
name: rx.prop<string>(),
icon: rx.prop<string>(),
active: rx.prop<boolean>({ defaultValue: false }),
additionalText: rx.prop<string>({ defaultValue: '' }),
}

private btnRef = this.ref<ui5.types.Button>();

render() {
const { name, icon, active, additionalText } = this.props;

return [
ui5.button({
ref: this.btnRef,
events: {
click: e => this.reDispatch('click', e)
},
classes: { active },
fields: {
design: active.ifelse({ if: 'Default', else: 'Transparent' }),
}
}, [
ui5.icon({ fields: { name: icon }}),
h.div(name),
h.div(
{ fields: { id: 'additional-text' } },
additionalText.derive(at => ` (${at})`),
)
]),
]
}

override focus() { this.btnRef.current.focus(); }

static styles = style.sheet({
'ui5-button': {
height: '6em',
width: '6em',
margin: '0.3em',
},
'ui5-icon': {
height: '1.5em',
width: '1.5em',
marginBottom: '0.3em',
},
'#additional-text': {
color: ui5.Theme.NeutralTextColor,
opacity: ui5.Theme.Content_DisabledOpacity,
},
});
}
2 changes: 1 addition & 1 deletion src/renderer/document/CanvasSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ export class CanvasSelection {
width: dim * 2, height: dim * 2,
});
return (el instanceof SVGPathElement)
? new CanvasPath(el).isTouchingRect(fakeSelRect)
? (el.hasAttribute('d') && new CanvasPath(el).isTouchingRect(fakeSelRect))
: SVGUtils.rectIntersect(selRect, elRect);
} else { // actual rectangle
return SVGUtils.rectInRect(selRect, elRect);
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/document/CanvasTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { WournalPage } from "./WournalPage";
export const CanvasToolNames = [
"CanvasToolPen",
"CanvasToolHighlighter",
"CanvasToolRuler",
"CanvasToolEraser",
"CanvasToolRuler",
"CanvasToolRectangle",
"CanvasToolEllipse",
"CanvasToolSelectRectangle",
Expand Down

0 comments on commit 6a5aaa9

Please sign in to comment.