Change the 'config' attribute of an interactor for disabling some user events - xtk

I'd like to display several views of the same scene, with 1 of them full interactive, and 2 others from top and right and which could only be zoomed. So my issue is to disable some user interactions on a render.
One alternative is to overload the other events handler methods with forcing the renderer's camera to keep the same view if the event isn't a mouse wheel. It works but it's not pretty (neither for a programmer nor a user).
So I want to change the 'config' attribute of my renderer. Here is my code and the explained issues :
var r1 = new X.renderer('r1'); // r1 is created, but its "interactor" attribute is null, see visualization>renderer.js
r1.interactor().config.MOUSEWHEEL_ENABLED = false; // DO NOT work cause the "interactor" attribute of r1 is null
r1.init(); // r1 is initialized : it creates a new interactor, calls interactor.init(), and puts the new interactor in the "interactor" attribute of r1, , see visualization>renderer.js
r1.interactor().config.MOUSEWHEEL_ENABLED = false; // DO NOT work because the interactor.init() has already generated all the event handler methods and associated them to the listeners, see io>interactor.js
I also tried the following but in consequence my renderer turns black/empty :
var r1 = new X.renderer('r1');
r1.init();
r1.interactor().config.MOUSEWHEEL_ENABLED = false;
r1.interactor().init();
Do you see the issue ? The 'config' change should be done between the creation of a new interactor and the initialization of it. But, if I'm not mistaken, you cannot create an interactor and set it to a renderer manualy like the "interactor" attribute is protected.
Did I something wrong ? Any idea to perform it ?

This is the correct way to do it
var r1 = new X.renderer('r1');
r1.init();
r1.interactor().config.MOUSEWHEEL_ENABLED = false;
r1.interactor().init();
but you were right - it didn't work so far because of a typo and a missing exported symbol. This was fixed in https://github.com/xtk/X/commit/f1f80ebb26020f4b13b797993a9008ae07a50195
and is available in http://get.goxtk.com/xtk_edge.js now.

Related

Dynamic theme color at run time jetpack compose

I'm new to Jetpack Compose, so I'm struggling to implement a feature which is dynamic colors (and font, size,... but I think they are the same so I'll just focus on color) at run time from backend. I'll let the app the some default colors, and a whole default splash screen just to load the colors setting from the backend. In case the API request failed, it would use the last succeeded requested colors or just the default color.
Tutorials I found round the internet was just about changing the dark/light theme at run time, not changing a specific color in the color pack. In those tutorials, the color is defined in Colors.kt file which is not a composable or class or object, ...
I imagine the color within lightColors or darkColors would be something like this.
return lightColors(
primary = Color(android.graphics.Color.parseColor("#" + dynamicColorMap["One"])),
...
}
And when dynamicColorMap changes in the splashscreen, all screen later will have reference to the new value, but I don't know how to update its variable outside of a composable.
I thought of using DB to store the colors, but getting the data from DB is async, so it cannot be query in the default Colors.kt like var colorOne = DBManager.getColor("One"), I can run the async task in my splash screen before changing to the next screen but then the problem again is how to have a global state that my theme composable wrapper can have access to on every screen?
I just don't know where to start for these case.
Thank you for your time
EDIT:
I currently having the project structured in MVVM. For now, only one activity (MainActivity) is present, and inside that activity, the splash screen component or home screen or login screen,... are being navigated. So is it a good practice to create a viewmodel for the mainactivity screen, that can holds the color state for the theme?
Thanks #Maciej Ciemiega for the suggestion. I ended up structure my code like that.
In my MainActivity.kt I create a viewmodel for it.
val mainActivityViewModel by viewModels<MainActivityViewModel>()
MyTheme(mainActivityViewModel = mainActivityViewModel) {
initNavigationController(navController)
Surface(color = MaterialTheme.colors.background) {
if (mainActivityViewModel.appSettingsState.value.appSettings.colorsMapLight.size != 0
&& mainActivityViewModel.appSettingsState.value.appSettings.colorsMapDark.size != 0) {
navController.navigate(NavigationDestinations.homeScreen)
}
}
}
my initNavigationController function shows the splashscreen first. But it doesn't do anything. The getting app settings configuration is called in MyTheme composable via the mainActivityViewModel, and MyTheme will use the state from the viewmodel to define the theme, and the navController.navigate is based on the state as you guys can see in the if above.
I don't know if this is a good practice or not, or when my app grows it would be a mess or not, but at least it works for me. I tried with font styles too and it works like a charm.

Set custom chipDrawable background to Chip

I want to set custom drawable background to Chip, just like that chip.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.bg_cutom_drawable));
But it is not working.It gives an error
java.lang.UnsupportedOperationException: Do not set the background resource; Chip manages its own background drawable.
It required a chipDrawable. How to create chipDrawable for same. I tried but not able to find out solution.
Please suggest me it would be appreciate.
if you want change background color, you can try:
ChipDrawable chipDrawable = (ChipDrawable)chip.getChipDrawable();
chipDrawable.setChipBackgroundColorResource(R.color.colorPrimary);
Using this code you can generate multicolor chip.
add this code in oncreate() or anywhere in function
// "i" is integer value and it will be unique for every chip. In my case I have put in chip in FOR loop that why "i" is there
Chip chip = (Chip) LayoutInflater.from(getActivity()).inflate(R.layout.item_content_lang_chip, null);
chip.setText(contentLangModels.get(i).getContentDisplay());
chip.setId(i);
chip.setChipBackgroundColor(buildColorStateList(getActivity(),"#1e61d5","#2e2e37"));
chipGrpContentType.addView(chip);
Add below function in your activity
public ColorStateList buildColorStateList(Context context, String pressedColorAttr, String defaultColorAttr){
int pressedColor = Color.parseColor(pressedColorAttr);
int defaultColor = Color.parseColor(defaultColorAttr);
return new ColorStateList(
new int[][]{
new int[]{android.R.attr.state_checked},
new int[]{} // this should be empty to make default color as we want
}, new int[]{
pressedColor,
defaultColor
}
);
}
Do not use the android:background attribute. It will be ignored because Chip manages its own background Drawable
chip document
If someone is using a material chip inside a dialog and getting a crash with same above error then you need to remove background attribute for your dialog set from styles.

How to work with the input and output handers in famo.us?

In order to build clean code, Famo.us is using events to communicate to modules. Most of the Event guide shows example about EventHandler. Now we are supposed to build robust view with input and output events, how to actually work with it ? i.e. what is the purpose of the input and output handlers ?
In order to build robust modules is is convenient to separate the code into Widgets which are only responsible for the function they are built for. Here is the official way of building a widget:
function Widget(){
this.eventOutput = new EventHandler();
this.eventInput = new EventHandler();
EventHandler.setInputHandler(this, this.eventInput);
EventHandler.setOutputHandler(this, this.eventOutput);
}
var widget = new Widget();
To summarise the function above it does create an object with 2 EventHandler, one for the input and another one for the output.
Their purpose is trivial:
all the incoming events i.e. the events triggered from outside of the widget object will be triggered to the eventInput handler.
all the outgoing events i.e. events generated by the widget to the outside are triggered through the eventOutput.
To understand a little better, you will very likely be listening to an eventInput handler from inside of the widget and trigger to an eventOutput handler still from inside of the widget code.
Here is an example:
function Widget(){
// here we are inside the Widget code scope
var self = this; // just to keep the root "this" somewhere
this.eventOutput = new EventHandler();
this.eventInput = new EventHandler();
this.eventInput.on("sayHello", function()
{
alert("Hello")
});
function didSomething()
{
self.eventOutput.trigger("didSomething");
}
}
You might then use the widget as follow:
var widget = new Widget();
widget.eventOutput.on("didSomething", function(){alert("The widget did something!")})
widget.eventInput.trigger("sayHello"); // will alert "Hello" from inside the widget
Now we might not be willing to know the internal structure of a widget to use it. Here we are calling and listening on the eventOutput and eventInput which might actually have any name. For the clarity of the code, we can bind those events functions to the widget itself adding the following lines into the widget:
... code ...
EventHandler.setInputHandler(this, this.eventInput);
EventHandler.setOutputHandler(this, this.eventOutput);
... code ...
Now the widget can be listened and triggered in the following way:
widget.on("didSomething", function(){alert("The widget did something!")});
widget.trigger("sayHello"); // will let the widget alert "Hello"
What about piping ?
This is quite simple, while piping a widgetA to a widgetB
widgetA.pipe(widgetB);
All the events triggered by widgetA.eventOutput are piped (read triggered) to widgetB.eventInput
Note: The same principle can be applied on subscription, the following will achieve exactly the same result:
widgetB.subscribe(widgetA);

How to close a MFC CVIEW while keeping the document open

I have a MFC CDocument and associated CView open in a MDI application. I would like to detach and close the view (and associated frame), while keeping the document open. Looking around the MFC code to see how it does it, reveals the following in CDocument::OnCloseDocument();
// destroy all frames viewing this document
// the last destroy may destroy us
BOOL bAutoDelete = m_bAutoDelete;
m_bAutoDelete = FALSE; // don't destroy document while closing views
while (!m_viewList.IsEmpty())
{
// get frame attached to the view
CView* pView = (CView*)m_viewList.GetHead();
ASSERT_VALID(pView);
CFrameWnd* pFrame = pView->EnsureParentFrame();
// and close it
PreCloseFrame(pFrame);
pFrame->DestroyWindow();
// will destroy the view as well
}
m_bAutoDelete = bAutoDelete;
which I guess I could use in conjunction with CDocument::RemoveView. Is there a better way to approach this than just lifting the MFC source, and is this approach going to cause me other problems or side effects? The project is VS2010 C++.
If you set CDocument::m_bAutoDelete to FALSE (after the document has been created) it should not delete the document when the last view closes.
I'm not sure what you're specifically trying to do but you might want to consider creating a separate 'data' object that can be attached to a document rather than trying to keep the document itself around.

Configuring new document in MFC

When the user creates a new document in my SDI-application, I need to present a dialog specifying details on the document to be created (think: resolution, bit-depth, etc.) I initially put the code for displaying this dialog in OnNewDocument() (I don't need it when opening an existing document), but putting user-interface code in the document-class just doesn't feel right (also, I don't have any CWnd* to use as a parent for the dialog).
Is there a better place to do this in MFC?
You're right, the document class is no good place for UI.
CDocTemplate::[OpenDocumentFile][1](pszPath) looks like a better candidate:
pszPath==NULL means 'create a new document'.
The method is virtual -> Just derive CMySingleDocTemplate from CSingleDocTemplate and use an instance of this class in CMyWinApp::InitInstance().
This class is responsible for creating docs, frames and views, hence I think it's a good place to put a UI operation.
BOOL CMyWinApp::InitInstance()
{
...
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CMySingleDocTemplate( // <--Derives from CSingleDocTemplate
IDR_MAINFRAME,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CMyView));
AddDocTemplate(pDocTemplate);
...
}
CDocument* CMySingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
BOOL bMakeVisible)
{
CDocument *pDoc =
CSingleDocTemplate::OpenDocumentFile(lpszPathName, bMakeVisible);
if (lpszPathName==NULL)
{
// GUI to get user info
// update doc
m_pOnlyDoc->Blah(input);
// update view
m_pOnlyDoc->UpdateAllViews(NULL,...,...);
}
}
This might not be ideal though: In SDI, there is one and only doc object. It's re-used accross File/Load and File/New operation.
This function will then be called a first time before the initial mainframe is created. You may not want to have a dialog presented to user before the frame is created. Ouch! It's a little more complicated:
Instead of popping up a GUI in in OpenDocumentFile(NULL) as above, just post a custom message/command to the main frame. Then add a handler that will react by the sequence pop up GUI/update doc/update views. That way, the main frame will be displayed before the GUI is popped up and your user will be happier.
This also solves your problem where you don't have a CWnd parent: the main frame is already created and your dialog will use it byt default.
BTW, another solution consists in adding a command handler for ID_FILE_NEW in your CMyWinApp's message map and add your own override of OnFileNew(). But when you write OnFileNew(), I believe you'll quickly find out that it's an ugly solution :-(