Skip to content

Commit

Permalink
Merge branch 'lit-device-panel'
Browse files Browse the repository at this point in the history
* Branch commit log:
  ui/b/shell.vue: leave overflow and padding to <b-devicepanel/>
  ui/b/devicepanel.js: port to LitComponent from Vue
	* Adjust horizontal scroll shadows
	* Move overflow scrolling to be handled inside devicepanel
	* Fix sibling handling in menuopen, fixes #46
	* Open menu on press, feels faster
	* Port to use LitComponent and repeat()
	* Make use of the device.devs property
	* Remove devicepanel.vue
  ase/api, ase/device*: add Device.devs property
  ui/b/contextmenu.js: avoid binding foreign callbacks to contextmenu
  ui/tailwind.scss: add .hflex and .vflex classes
  ui/Makefile.mk: leave "fixme" linting to synsmell, check all files
  misc/synsmell.py: extend CSS heuristic

Signed-off-by: Tim Janik <[email protected]>
  • Loading branch information
tim-janik committed Jun 9, 2024
2 parents 0c69d0f + f925527 commit 4ebbc09
Show file tree
Hide file tree
Showing 12 changed files with 219 additions and 159 deletions.
6 changes: 5 additions & 1 deletion ase/api.hh
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ struct DeviceInfo {

/// Interface to access Device instances.
class Device : public virtual Gadget {
virtual bool devs_ (const DeviceS *n, DeviceS *q);
protected:
explicit Device ();
public:
// internal
Track* _track () const; ///< Find Track in parent ancestry.
Expand All @@ -222,19 +225,20 @@ public:
// exported
virtual bool is_active () = 0; ///< Check whether this is the active synthesis engine project.
virtual DeviceInfo device_info () = 0; ///< Describe this Device type.
virtual DeviceS list_devices () = 0; ///< List devices in order of processing, notified via "devs".
void remove_self (); ///< Remove device from its container.
// GUI handling
virtual void gui_toggle () = 0; ///< Toggle GUI display.
virtual bool gui_supported () = 0; ///< Has GUI display facilities.
virtual bool gui_visible () = 0; ///< Is GUI currently visible.
Member<&Device::devs_> devs [[no_unique_address]];
};

/// Interface to access NativeDevice instances.
class NativeDevice : public virtual Device {
public:
// subdevice handling
virtual bool is_combo_device () = 0; ///< Retrieve wether this NativeDevice handles sub devices.
virtual DeviceS list_devices () = 0; ///< List devices in order of processing, notified via "devices".
DeviceInfoS list_device_types (); ///< List registered Device types with their unique uri.
virtual void remove_device (Device &sub) = 0; ///< Remove a directly contained device.
virtual DeviceP append_device (const String &uri) = 0; ///< Append a new device, see list_device_types().
Expand Down
17 changes: 17 additions & 0 deletions ase/device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@

namespace Ase {

// == Device ==
Device::Device() :
devs (this, "devs")
{}

bool
Device::devs_ (const DeviceS *n, DeviceS *q)
{
if (n) {
// no assignments
// devs.notify();
}
if (q)
*q = list_devices();
return true;
}

// == DeviceImpl ==
void
DeviceImpl::_set_parent (GadgetImpl *parent)
Expand Down
1 change: 1 addition & 0 deletions ase/device.hh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ protected:
public:
void _activate () override;
void _deactivate () override;
DeviceS list_devices () override { return {}; }
bool is_active () override { return activated_; }
bool gui_supported () override { return false; }
bool gui_visible () override { return false; }
Expand Down
2 changes: 2 additions & 0 deletions ase/nativedevice.cc
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ NativeDeviceImpl::remove_device (Device &sub)
proc_->engine().async_jobs += j;
// once job is processed, dtor runs in mainthread
}
devs.notify();
}

DeviceP
Expand Down Expand Up @@ -157,6 +158,7 @@ NativeDeviceImpl::insert_device (const String &uri, Device *sibling, const Devic
};
proc_->engine().async_jobs += j;
}
devs.notify();
return devicep;
}

Expand Down
2 changes: 1 addition & 1 deletion ase/nativedevice.hh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public:
bool is_combo_device () override { return combo_ != nullptr; }
DeviceInfo device_info () override { return info_; }
// handle sub Devices
DeviceS list_devices () override { return children_; }
DeviceS list_devices () override { return children_; }
void remove_device (Device &sub) override;
DeviceP append_device (const String &uri) override;
DeviceP insert_device (const String &uri, Device &beforesibling) override;
Expand Down
3 changes: 2 additions & 1 deletion misc/synsmell.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ def line_matcher (code, text, has_comment, orig, filename):
error = "invalid call to printf"
# whitespace-before-parenthesis
elif m := checks['whitespace-before-parenthesis'] and code.find ('#') < 0 and re.search (r'\s\w+[a-z0-9]\([^)]', code, re.IGNORECASE):
if not re.search (r'\s\.|:\s', code): # ignore funcs in CSS rules
if (not re.search (r'\s\.|:\s|@import', code) and # ignore funcs in CSS rules
not filename.endswith ('css')):
m = m.end() - 2
warning = "missing whitespace before parenthesis"
# whitespace-after-parenthesis
Expand Down
7 changes: 2 additions & 5 deletions ui/Makefile.mk
Original file line number Diff line number Diff line change
Expand Up @@ -317,12 +317,9 @@ CLEANDIRS += $>/tscheck/
# == ui/lint ==
ui/lint: | node_modules/.npm.done
$(QGEN)
$(MAKE) --no-print-directory NPMBLOCK=y -j1 \
eslint tscheck $>/ui/global.css
$(MAKE) --no-print-directory NPMBLOCK=y -j1 eslint tscheck
-$Q node_modules/.bin/stylelint $${INSIDE_EMACS:+-f unix} -c ui/stylelintrc.cjs $(wildcard ui/*.*css ui/b/*.*css)
-$Q { TCOLOR=--color=always ; tty -s <&1 || TCOLOR=; } \
&& grep $$TCOLOR -nE '(/[*/]+[*/ ]*)?(FI[X]ME).*' -r ui/ --exclude '*.js'
$Q misc/synsmell.py --separate-body=0 ui/*js ui/b/*.js
$Q misc/synsmell.py --separate-body=0 ui/*.* ui/b/*.*
.PHONY: ui/lint
lint: ui/lint

Expand Down
3 changes: 2 additions & 1 deletion ui/b/contextmenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ class BContextMenu extends LitComponent {
}
async toggle_active_children()
{
const isactive = async uri => !uri || !this.isactive || await this.isactive (uri);
const this_isactive = this.isactive; // fetch function property *not* bound to contextmenu
const isactive = async uri => !uri || !this_isactive || await this_isactive (uri);
const proms = [];
for (let b of this.querySelectorAll ('button,push-button')) {
/**@type{any}*/ const any = b;
Expand Down
169 changes: 169 additions & 0 deletions ui/b/devicepanel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
// @ts-check

/** @class BDevicePanel
* @description
* Panel for editing of devices.
* ## Props:
* *track*
* : Container for the devices.
*/

import { LitComponent, html, render, noChange, JsExtract, docs, ref, repeat } from '../little.js';
import * as Util from "../util.js";
import * as Kbd from '../kbd.js';
import { text_content, get_uri, valid_uri, has_uri } from '../dom.js';

// == STYLE ==
JsExtract.css`
$scrollbar-height: 6px; //* Should match Firefox 'scrollbar-width:thin' */
b-devicepanel {
@apply hflex;
padding: 0 0 3px 0;
background: $b-devicepanel-bg;
border-radius: inherit;
overflow: hidden;
.b-devicepanel-scroller {
@apply hflex;
overflow: auto visible;
justify-content: flex-start;
align-items: center;
}
.b-devicepanel-vtitle {
text-align: center;
/* FF: writing-mode: sideways-rl; */
writing-mode: vertical-rl;
transform: rotate(180deg);
border-right: 7px solid #9c61ff;
padding: 1em 5px;
border-top-right-radius: inherit;
border-bottom-right-radius: inherit;
align-self: stretch;
//* Add slight shadow to the right for a soft scroll boundary */
box-shadow: -2px 0 $b-scroll-shadow-blur 0px #000;
background: #000000ef;
z-index: 9; //* raise above scrolled siblings */
}
.b-devicepanel-hstack {
align-self: stretch;
padding-top: $scrollbar-height;
padding-bottom: 0;
> * { flex-grow: 0; }
.b-more { margin-top: $scrollbar-height; }
}
position: relative;
&::after {
position: absolute; left:0; top:0; right:0; bottom:0;
content: ' '; pointer-events: none;
box-shadow: inset -10px 0 7px -7px #000, inset 10px 0 7px -7px #000;
z-index: 9; //* raise above scrolled siblings */
}
}`;

// == HTML ==
const DEVICE_HTML = (t, dev) => html`
<b-more @mousedown=${e => t.menuopen (e, dev)}
data-tip="**CLICK** Add New Elements" ></b-more>
<b-deviceeditor .device=${dev} center ></b-deviceeditor>
`;
const HTML = (t) => html`
<div class="b-devicepanel-scroller" >
<span class="b-devicepanel-vtitle"> Device Panel </span>
<h-flex class="b-devicepanel-hstack" >
${repeat (t.chain_?.devs || [], dev => dev.$id, dev => DEVICE_HTML (t, dev))}
<b-more @mousedown=${e => t.menuopen (e)}
data-tip="**CLICK** Add New Elements" ></b-more>
<b-contextmenu ${ref (h => t.devicepanelcmenu = h)}
id="g-devicepanelcmenu" .activate=${t.activate.bind (t)} .isactive=${t.isactive.bind (t)} >
<b-menutitle> Devices </b-menutitle>
<b-treebrowser .tree=${t.devicetypes} ?expandall="false"> </b-treebrowser>
</b-contextmenu>
</h-flex>
</div>
`;

// == SCRIPT ==
import * as Ase from '../aseapi.js';

/**
* @param {Ase.Device} [device] - Track device.
*/
async function list_device_types (device)
{
const deviceinfos = await device.list_device_types(); // [{ uri, name, category, },...]
const cats = {};
for (const e of deviceinfos) {
const category = e.category || 'Other';
cats[category] = cats[category] || { label: category, type: 'resource-type-folder', entries: [] };
e.label = e.label || e.name;
cats[category].entries.push (e);
}
const list = [];
for (const c of Object.keys (cats).sort())
list.push (cats[c]);
return Object.freeze (list);
}

class BDevicePanel extends LitComponent {
createRenderRoot() { return this; }
render() { return HTML (this); }
static properties = {
track: { type: Ase.Track, reflect: true },
};
constructor()
{
super();
this.track = null;
this.chain_ = null;
this.menu_sibling = null;
this.devicepanelcmenu = null;
}
updated (changed_props)
{
let info_promise;
if (changed_props.has ('track')) {
this.chain_ = null;
const track_fecth_device = async () => {
const chain = await this.track.access_device();
const devicetypes = await list_device_types (chain);
this.devicetypes = devicetypes;
this.chain_ = chain;
this.request_update();
};
if (this.track)
track_fecth_device();
}
}
async activate (uri)
{
// close popup to remove focus guards
if (this.chain_ && !uri.startsWith ('DevicePanel:')) // assuming b-treebrowser.devicetypes
{
const sibling = this.menu_sibling;
let newdev;
if (sibling)
newdev = this.chain_.insert_device (uri, sibling);
else
newdev = this.chain_.append_device (uri);
this.menu_sibling = null;
newdev = await newdev;
if (!newdev)
console.error ("Ase.insert_device failed, got null:", uri);
}
}
isactive (uri)
{
if (!this.track)
return false;
return true;
}
menuopen (event, sibling)
{
this.menu_sibling = sibling;
this.devicepanelcmenu.popup (event, { origin: 'none' });
Util.prevent_event (event);
}
}
customElements.define ('b-devicepanel', BDevicePanel);
Loading

0 comments on commit 4ebbc09

Please sign in to comment.