Sunday, 3 July 2016

Completion thread pool for C++


This is an implementation of a thread pool for c++ I wrote a month ago. It has two classes, the general ThreadPool that accepts new tasks and returns std::future to receive the result from them and the CompletionThreadPool that works more along the lines of ExecutionCompletionService from java. The CompletionThreadPool Based on regular thread pool allowa to retrieve tasks results in order of the completion. It can be used as follows. Create a task to be submitted to the pool:
int f(int sleep_time) {
    sleep(sleep_time);
    return sleep_time;
}
Create CompletionThreadPool instance with designated task result type:
CompletionThreadPool completionThreadPool;
Submit any number of tasks for execution (they will be enqueued for execution immediately):
completionThreadPool.Submit(f, 5);
completionThreadPool.Submit(f, 1);
Block waiting for the results in order of their completion:
std::future firstCompleted = completionThreadPool.Take();
std::future secondCompleted = completionThreadPool.Take();
The source is located at github. There is also a qt sample application that uses CompletionThreadPool to download images in separate threads and show them in a window in order of readiness.

Friday, 13 November 2015

How to link pre-built library with CMake


1. Provide path to library (for example, default path may be set to usr/local/lib on Linux, and the lib won't be found even when located in the same directory as CMakeLists.txt and even with full path provided inside target_link_libraries). Suppose library is in the subfolder /lib of the folder where CMakeLists.txt resides, then:
set(PATH_TO_LIB ${CMAKE_CURRENT_LIST_DIR}/lib/)
find_library(MyLibVariable NAMES "MyLibrary" PATHS ${PATH_TO_LIB} NO_DEFAULT_PATH)
NAMES should provide the name of library, without the lib prefix. So if there is libMyLibrary.so it shoud read "MyLibrary". NO_DEFAULT_PATH removes all default paths from search. CMAKE_CURRENT_LIST_DIR is the directory where CMakeLists.txt is located.

2. Use target_link_libraries on the found library, presented by MyLibVariable
target_link_libraries(${APP_NAME} 
    ${MyLibVariable}
)
APP_NAME is the name of application to link the library to, added with add_executable(${APP_NAME} ${SRC} ${HEADERS}) in this CMakeLists.txt
In case the library still cannot be located you can debug the path is really the one you suppose it should be, including in CMakeLists.txt the following:
MESSAGE('--- MyLibVariable ---')
MESSAGE(${MyLibVariable})
In case path is still wrong make sure to delete the CMakeCache.txt, as it might have cached previous value.

Monday, 28 September 2015

Morphing animation for Toolbar back button and Navigation drawer icon (Android)


It is common to use one of the third-party libs to create a morphing animation for icon, I have used the popular material-menu library. With this libray it is easy to use to morph animation for the navigation drawer icon, or any other icon in ui. However, the problem came up when I wanted to animate the transition from the Navigation drawer burger icon to Toolbar back button. The scenario is as follows. There is a Navigation drawer icon on the left side of Toolbar, also there is a collapsed SearchView in Toolbar. When the user clicks on search icon on the left side of Actionbar, SearchView expands and the burger icons turns into the back icon. Pressing this back button hides SearchView. The desired effect is to morph the back button into the hamburger icon and vice versa.

This is easier said then done because the burger button and back button are actually two different buttons. But, looking into Android source for android.support.v7.widget.Toolbar it is obvious that the two buttons are actually mNavButtonView and mCollapseButtonView, and they luckily have the same layout parameters and positioning (see ensureNavButtonView() and ensureCollapseButtonView() methods).

Now, the basic idea is to setup the same morphing drawable on both buttons, and play animation on them simultaneously - and hence animation will always be seen irrespective of the current visible button. For the Navigation drawer button drawable can be set simply with the call to setHomeAsUpIndicator(). To set the back button drawable we must use reflection to get to the mCollapseButtonView field and ensureCollapseButtonView() method. We need to call the ensureCollapseButtonView() method first to make sure that the mCollapseButtonView is created.


import com.balysv.materialmenu.MaterialMenuDrawable;

...


private MaterialMenuDrawable mToolbarMorphDrawable;
private MaterialMenuDrawable mSearchViewMorphDrawable;

... 

private void setupActionBar(final Toolbar toolbar) {
  
mToolbarMorphDrawable = new MaterialMenuDrawable(this, Color.BLACK,
                                           MaterialMenuDrawable.Stroke.THIN);
    
mToolbarMorphDrawable.setIconState(MaterialMenuDrawable.IconState.BURGER);
 
mSearchViewMorphDrawable = new MaterialMenuDrawable(this, Color.BLACK, 
                                           MaterialMenuDrawable.Stroke.THIN);

mSearchViewMorphDrawable.setIconState(MaterialMenuDrawable.IconState.BURGER);

Toolbar toolbar = setupActionBar((Toolbar) findViewById(R.id.upperToolbar));
setSupportActionBar(toolbar);
final ActionBar ab = getSupportActionBar();
if (ab != null) {
    ab.setHomeAsUpIndicator(mToolbarMorphDrawable);
    ab.setDisplayHomeAsUpEnabled(true);
}

try {
    Method ensureCollapseButtonView = android.support.v7.widget.Toolbar.class
                        .getDeclaredMethod("ensureCollapseButtonView", null);

    ensureCollapseButtonView.setAccessible(true);
    ensureCollapseButtonView.invoke(toolbar, null);

    Field collapseButtonViewField = android.support.v7.widget.Toolbar.class.
                                    getDeclaredField("mCollapseButtonView");

    collapseButtonViewField.setAccessible(true);

    ImageButton imageButtonCollapse = (ImageButton) collapseButtonViewField
                                                             .get(toolbar);

    imageButtonCollapse.setImageDrawable(mSearchViewMorphDrawable);
}
catch (Exception e) {
    // Something went wrong, let the app work without morphing the buttons :)
    e.printStackTrace(); 
}
}


That is the OnActionExpandListener that starts morphing animation when the expanded action view (SearchView in our case) expands and collapses.

MenuItemCompat.setOnActionExpandListener(searchMenuItem, 
                            new MenuItemCompat.OnActionExpandListener() {
            @Override
            public boolean onMenuItemActionCollapse(MenuItem item) {
                mToolbarMorphDrawable.animateIconState(MaterialMenuDrawable
                                                         .IconState.BURGER);
                mSearchViewMorphDrawable.animateIconState(MaterialMenuDrawable
                                                         .IconState.BURGER);
                return true;
            }

            @Override
            public boolean onMenuItemActionExpand(MenuItem item) {
                mToolbarMorphDrawable.animateIconState(MaterialMenuDrawable
                                                          .IconState.ARROW);
                mSearchViewMorphDrawable.animateIconState(MaterialMenuDrawable
                                                          .IconState.ARROW);
                return true;
            }
        });


You might ask, why there are two separate drawables for these two buttons. Yes, we might have designated one drawable instance but then the animation wouldn't work as expected because one of the buttons "locks" the drawable and this makes the animation to freeze when another button becomes invisible.

Note that the reflection is used on the android.support.v7.widget.Toolbar.class, but if you use android.widget.Toolbar then change this line. Other than that android.widget.Toolbar seems to have the same fields and methods names so that you can try the same technique for it.