I seem to have a problem with the pack-figure and using computeFigure.
Below is some code to reproduce the behaviour I have.
public void main() {
bool redraw = false;
str boxWidthProp = "";
Figure topBar = hcat([text("Width"), combo(["1", "2"], void(str s){ boxWidthProp = s; }, hshrink(0.1))
, button("Redraw", void() {redraw = true; }, resizable(false))], vshrink(0.05), hgap(5));
Figure getTreemap() {
return computeFigure(bool () { bool temp = redraw; redraw = false; return temp; }, Figure() {
int sz = 20;
if (boxWidthProp == "2")
sz = 100;
b = box(size(sz, sz), fillColor("Red"), resizable(false));
t = text(str() {return "w: <sz>; prop: <boxWidthProp>"; });
Figures boxes = [];
boxes += b;
boxes += t;
//return pack(boxes, std(gap(5)));
return vcat([t,b]);
});
}
vc = vcat([topBar, getTreemap()]);
render(vc);
}
When running this code, you get a new screen with a combo, button, label and a box.
When you change the combo you'll see the value of the label change.
When you click the button the box will change (it's size).
When you change the combo again, you'll see the label change and clicking - The button will do it's job again.
This can continue.
Now uncomment the line "return pack ..." and comment "return vcat".
Run the code again.
You will see the same screen.
Changing the combo works.
Clicking the button will change the box.
But from now on everything stops.
Changing the combo, nothing.
Clicking the button, nothing.
My guess here is that there is a problem with the pack-figure. But I'm a total newbie with rascal (and eclipse), so it might be that I'm missing something.
Related
I am facing a problem on PrimeNG TurboTable.
I started from the following example: https://www.primefaces.org/primeng/#/table/selection and more particularly from the Checkbox Selection example.
The only difference is that on some p-tableCheckbox I added a [disabled]="true"
This works very well if I select a disabled line it does not activate and can not be selected, but when I click on p-tableHeaderCheckbox all the lines are selected even the lines in disabled.
In addition, the selection also counts the lines in status disabled or it should only take lines with no status disabled
I made an example on stackblitz : https://stackblitz.com/edit/angular-gnbsml?file=src%2Fapp%2Fapp.component.html
How to prevent tableHeaderCheckbox from also selecting disable lines?
Thank you in advance for your answers
You can prevent selection in (selectionChange) callback on table. Split [(selection)] on two part:
[selection]="selectedRowData" (selectionChange)="onSelectionChange($event)"
Add onSelectionChange method to component:
onSelectionChange(selection: any[]) {
for (let i = selection.length - 1; i >= 0; i--) {
let data = selection[i];
if (this.isRowDisabled(data)) {
selection.splice(i, 1);
}
}
this.selectedRowData = selection;
}
Also add isRowDisabled method:
isRowDisabled(data: any): boolean {
return data.color === 'orange'
}
and change template for tableCheckbox to use isRowDisabled (it's only for check in one place)
<p-tableCheckbox [value]="rowData" [disabled]="isRowDisabled(rowData)"></p-tableCheckbox>
See example on https://stackblitz.com/edit/angular-hnzxs2 (I am also add logic to exclude disabled rows from process of calculating state of headerCheckBox)
It's failing when we have only disabled rows after filter. I have fixed it by checking active rows.
ngAfterViewInit(): void {
const orig_updateCheckedState = this._headerCheckBox.updateCheckedState;
const me = this;
this._headerCheckBox.updateCheckedState = function() {
const cars: any[] = me._table.filteredValue || me._table.value;
const selection: any[] = me._table.selection;
let actRows: boolean = false;
for (const car of cars) {
if (!me.isRowDisabled(car)) {
actRows = true;
const selected = selection && selection.indexOf(car) >= 0;
if (!selected) return false;
}
}
if (actRows) {
return true
} else {
return false;
}
};
}
With the help of this question I was able to figure out how I can display a link inside a StyledText widget in SwT. The color is correct and even the cursor changes shape when hovering over the link.
So far so good, but the link is not actually clickable. Although the cursor changes its shape, nothing happens if clicking on the link. Therefore I am asking how I can make clicking the link to actually open it in the browser.
I thought of using a MouseListener, tracking the click-location back to the respective text the click has been performed on and then deciding whether to open the link or not. However that seems way too complicated given that there already is some routine going on for changing the cursor accordingly. I believe that there is some easy way to do this (and assuring that the clicking-behavior is actually consistent to when the cursor changes its shape).
Does anyone have any suggestions?
Here's an MWE demonstrating what I have done so far:
public static void main(String[] args) throws MalformedURLException {
final URL testURL = new URL("https://stackoverflow.com/questions/1494337/can-html-style-links-be-added-to-swt-styledtext");
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, true));
StyledText sTextWidget = new StyledText(shell, SWT.READ_ONLY);
final String firstPart = "Some text before ";
String msg = firstPart + testURL.toString() + " some text after";
sTextWidget.setText(msg);
sTextWidget.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
StyleRange linkStyleRange = new StyleRange(firstPart.length(), testURL.toString().length(), null, null);
linkStyleRange.underline = true;
linkStyleRange.underlineStyle = SWT.UNDERLINE_LINK;
linkStyleRange.data = testURL.toString();
sTextWidget.setStyleRange(linkStyleRange);
shell.open();
while(!shell.isDisposed()) {
display.readAndDispatch();
}
}
Okay I was being a little too fast on posting this question... There's a snippet that deals with exactly this problem and it shows, that one indeed has to use an extra MouseListener in order to get things working.
The snippet can be found here and this is the relevant part setting up the listener:
styledText.addListener(SWT.MouseDown, event -> {
// It is up to the application to determine when and how a link should be activated.
// In this snippet links are activated on mouse down when the control key is held down
if ((event.stateMask & SWT.MOD1) != 0) {
int offset = styledText.getOffsetAtLocation(new Point (event.x, event.y));
if (offset != -1) {
StyleRange style1 = null;
try {
style1 = styledText.getStyleRangeAtOffset(offset);
} catch (IllegalArgumentException e) {
// no character under event.x, event.y
}
if (style1 != null && style1.underline && style1.underlineStyle == SWT.UNDERLINE_LINK) {
System.out.println("Click on a Link");
}
}
}
});
Here's my pagination/infinite scrolling scenario:
Load the initial N with startAt().limit(N).once('value'). Populate a list items.
On scroll, load the next N. (I pass a priority to startAt() but that's tangential.)
When a new item is added, I'd like to pop it to the top of items.
If I use a .onChildAdded listener for step 3, it finds all the items including those I've already pulled in thus creating duplicates. Is there a better way?
Another method would be to use the .onChildAdded listener for the initial N in step 1 instead of .once, but when the initial N items come in I do items.add(item) to sort one after the other as they are already in order, but with the new one that comes in after the fact I need to somehow know it's unique so I can do items.insert(0, item) to force it to the top of the list. I'm not sure how to set this up, or if I'm off the mark here.
EDIT: Still in flux, see: https://groups.google.com/forum/#!topic/firebase-talk/GyYF7hfmlEM
Here's a working solution I came up with:
class FeedViewModel extends Observable {
int pageSize = 20;
#observable bool reloadingContent = false;
#observable bool reachedEnd = false;
var snapshotPriority = null;
bool isFirstRun = true;
FeedViewModel(this.app) {
loadItemsByPage();
}
/**
* Load more items pageSize at a time.
*/
loadItemsByPage() {
reloadingContent = true;
var itemsRef = f.child('/items_by_community/' + app.community.alias)
.startAt(priority: (snapshotPriority == null) ? null : snapshotPriority).limit(pageSize+1);
int count = 0;
// Get the list of items, and listen for new ones.
itemsRef.once('value').then((snapshot) {
snapshot.forEach((itemSnapshot) {
count++;
// Don't process the extra item we tacked onto pageSize in the limit() above.
print("count: $count, pageSize: $pageSize");
// Track the snapshot's priority so we can paginate from the last one.
snapshotPriority = itemSnapshot.getPriority();
if (count > pageSize) return;
// Insert each new item into the list.
// TODO: This seems weird. I do it so I can separate out the method for adding to the list.
items.add(toObservable(processItem(itemSnapshot)));
// If this is the first item loaded, start listening for new items.
// By using the item's priority, we can listen only to newer items.
if (isFirstRun == true) {
listenForNewItems(snapshotPriority);
isFirstRun = false;
}
});
// If we received less than we tried to load, we've reached the end.
if (count <= pageSize) reachedEnd = true;
reloadingContent = false;
});
// When an item changes, let's update it.
// TODO: Does pagination mean we have multiple listeners for each page? Revisit.
itemsRef.onChildChanged.listen((e) {
Map currentData = items.firstWhere((i) => i['id'] == e.snapshot.name);
Map newData = e.snapshot.val();
newData.forEach((k, v) {
if (k == "createdDate" || k == "updatedDate") v = DateTime.parse(v);
if (k == "star_count") v = (v != null) ? v : 0;
if (k == "like_count") v = (v != null) ? v : 0;
currentData[k] = v;
});
});
}
listenForNewItems(endAtPriority) {
// If this is the first item loaded, start listening for new items.
var itemsRef = f.child('/items').endAt(priority: endAtPriority);
itemsRef.onChildAdded.listen((e) {
print(e.snapshot.getPriority());
print(endAtPriority);
if (e.snapshot.getPriority() != endAtPriority) {
print(e.snapshot.val());
// Insert new items at the top of the list.
items.insert(0, toObservable(processItem(e.snapshot)));
}
});
}
void paginate() {
if (reloadingContent == false && reachedEnd == false) loadItemsByPage();
}
}
Load the initial N with startAt().limit(N).once('value'). Populate a list items.
On the first run, note the first item's priority, then start an onChildAdded listener that has an endAt() with that priority. This means it'll only listen to stuff from there and above.
In that listener, ignore the first event which is the topmost item we already have, and for everything else, add that to the top of the list.
Of course, on scroll, load the next N.
EDIT: Updated w/ some fixes, and including the listener for changes.
In my application I create a few buttons using D3 functions, but when they're displayed they do not have the circular borders like the hard coded buttons do:
"Menu" is hard coded, the other four buttons are from D3 functions
I first thought I had screwed up the classes of the buttons, but they do have the ui-corner-all class:
Why aren't they getting styled correctly? (There is no custom CSS applied besides the red text)
They should look along the lines of these examples:
http://demos.jquerymobile.com/1.4.2/checkboxradio-radio/
Edit:
Here's the D3 function:
this.initialLoad = function(){
//var data= ["First button with some long text in the descriptionnnnnnnnnnnnnnnnnnnnnnnnnnnn", "Second button with some long text in the description"];
console.log("initialLoad");
//Create the header
headerElem = d3.select("#uploadedCompany")
.append("p");
//add the required buttons for selecting the right sheet for the set
var Addedbuttons = d3.select("#TheButtons").selectAll("input")
.data(
function (){
var titlelist = Array();
for (var n = 0; n < numOfSheets; n++){
titlelist[n]= upLoadedData[n].title;
}
return titlelist;
}
)
.enter()
.append('label')
.attr('for',function(d,i){ return 'Statement_a'+i; })
.text(function(d) { return d; })
.append("input")
.attr("type", "radio")
.attr("name","stmntRadio")
.property('checked',function (d,i){if (i===pSI) return true; else return `false;})`
.attr("id", function(d,i) { return i; })
.attr("onClick", "rbStatementClicked(this)");
//make sure that the trendON is false
d3.select("#cbTrendOn").node().checked = false;
updateSheet();
$("#TheButtons").enhanceWithin();
};
I am assuming your #TheButtons DOM element is setup as a controlgroup with data-type="horizontal". In that case you just need to add .controlgroup("refresh") after the enhance within. Also, add the dynamic controls to the .ui-controlgroup-controls DIV within the controlgroup.
var Addedbuttons = d3.select("#TheButtons .ui-controlgroup-controls ").selectAll("input")
.data(data)
.enter()
.append("input")
.attr("type", "radio")
.attr("name","stmntRadio")
.attr("id", function(d,i) { return 'Statement_a'+i; })
.attr("onClick", "rbStatementClicked(this)")
.append('label')
.attr('for',function(d,i){ return 'Statement_a'+i; })
.text(function(d) { return d; })
;
$("#TheButtons").enhanceWithin().controlgroup("refresh");
Here is a DEMO
i have the following:
for(var i:Number = 1; i <= 10; i++) {
if ( eval("chk"+i).selected == false ) {
btnSubmit.enabled = false;
} else {
btnSubmit.enabled = true;
}
}
i have 10 boxes. If anyone of them is checked, then i enable the form submit button. for some reason, the above code works for only the 10th item. any ideas why?
You are looping through each checkbox in turn, and setting the submit button to be enabled if that checkbox is ticked, and disabled if it is not.
This means that the last checkbox is the only one that counts, since every checkbox undoes whatever the previous one did.
Try this instead:
btnSubmit.enabled = false;
for(var i:Number = 1; i <= 10; i++) {
if ( eval("chk"+i).selected == true ) {
btnSubmit.enabled = true;
}
}
Now you set the button to be disabled, and then only set it to be enabled if any checkbox is ticked.
add a break statement after the btnSubmit.enabled = true to stop looping immediately. small thing in this case.... but...