Draw beautiful diagram effortlessly on ipad. Click here to know more..

Sunday, December 2, 2012

Lekh Diagram

Lekh Diagram is a sketch recognition diagramming app for ipad.
Get Lekh Diagram from app store: https://itunes.apple.com/us/app/lekh-diagram/id576124115

What is sketch recognition?
Sketch recognition is a technology by which a computer recognizes your drawings. For example if you want to draw a circle, then draw a rough circle on touch screen or using digitizer. As a human being is not perfect in drawing perfect shapes, you almost never draw a perfect circle.
The sketch recognition technology helps computer to understand which is the perfect shape which closely matches to your drawing then it replaces your rough drawing with perfect shapes.

There are many applications of sketch recognition. One common application of sketch recognition technology is used in drawing diagrams. A user draws rough diagrams using touch/digitizer and the software application converts them into good looking diagrams with perfect shapes. Lekh Diagram is one such application for ipad.

Here is demo of Lekh Diagram:


Get Lekh Diagram from app store: https://itunes.apple.com/us/app/lekh-diagram/id576124115

Learn more about Lekh Diagram here: http://www.avabodh.com/lekh
Get update/news of Lekh Diagram on twitter: https://twitter.com/avabodh
Register for update/news of Lekh Diagram on email: http://www.avabodh.com/lekh/register



Sunday, April 1, 2012

How to implement UndoManager (with example in Java on Android)

Undo-redo is a must-to-have feature in editing programs. This blog post describes how to implement undo-redo in your program. The example taken here is in Java but the concept is very simple and can be implemented easily in any language. 
Here is idea to implement the undo-redo. First of all you need these: UndoManager - a class that implements undo-redo features. UserAction - an abstract base class for all user actions.
The operations in the UndoManager are: undo, redo, canUndo, canRedo, addAction And the operations in UserAction are: perform, undo
As said above, the UserAction abstracts user actions which user can undo. For example in text editing program, inserting a character at a particular cursor location is an action which user can undo. So you need to implement this abstract class for all type of user's undo-able actions. 
Lets start with some real code. The code here is taken from an Android app "Scratchpad" 
This is a simple drawing program using touch. User can draw on the screen using touch dragging on Android tablet screen. So the user action,in this case, is draw a stroke on canvas. A stroke is defined as the drawing done between users actions of starting touch drag and stopping touch drag. Here is UndoManager class:
import java.util.*;
public class UndoManager {
 private UndoManager(){
  undoActions = new Stack();
  redoActions = new Stack();
 }
 public boolean canUndo(){
  return undoActions.size() > 0;
 }
 public boolean canRedo(){
  return redoActions.size() > 0;
 }
 public void undo(){
  if(canUndo()){
   UserAction act = this.undoActions.pop();
   act.undo();
   redoActions.push(act);
  }
 }
 public void redo(){
  if(canRedo()){
   UserAction act = this.redoActions.pop();
   act.perform();
   undoActions.add(act);
  }
 }
 public void add(UserAction action){
  this.undoActions.push(action);
  this.redoActions.clear();
 }
 private Stack undoActions;
 private Stack redoActions;
}

The code for UserAction
public abstract class UserAction {
 public abstract void perform();
 public abstract void undo();
}
Here is code for StrokeAction
public class StrokeAction extends UserAction{
 public StrokeAction(DrawingStroke ds){
  this.stroke = ds;
 }
 @Override
 public void perform(){
  ObjectStore.instance.addObject(stroke);
 }
 @Override
 public void undo(){
  ObjectStore.instance.removeObject(stroke);
 }
 private DrawingStroke stroke;
}

Whenever the user completes a drawing stroke in Scratchpad, an object of DrawingAction is created. The ObjectManager in the code above contains the all stroke objects. Whenever user performs a drawing, we add the stroke to object manager. The drawing of all available objects are managed ObjectManager. And when user wants to undo, we simply remove the stroke from object manager. For simplicity and readability, I am not adding the code of ObjectManager here. 

The code of UndoManager and UserAction is very generic and can be used any application. UserActions has to be implemented for for each undo-able user action type. This implementation will be application dependent.

Wednesday, March 28, 2012

Making the iOS text field/view visible which is located under keyboard


The text view being hidden by keyboard is a very common issue faced by iPhone/iPad developers. When you touch a text view, the text view becomes first responder and keyboard automatically appears. If the text view is lying somewhere in lower part of the screen, most probably it will get hidden under the keyboard. The solution is to scroll the text view up enough so that it comes above the keyboard. To do that, you need to add the text view in UIScrollView so that it can be scrolled up.
Here is the strategy:
  • Whenever keyboard appear, check if it is hiding the text view or not.
  • If it is hiding the text view, then scroll the text view up so that it becomes visible.
  • When the keyboard disappears, then scroll the text view to its original position.
Here is the sample code (similar code used in Lekh Diagram):

First register for the keyboard appearing/disappearing event:
[[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(keyboardWasShown:)
            name:UIKeyboardDidShowNotification object:nil];
    
[[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(keyboardWillBeHidden:)
            name:UIKeyboardWillHideNotification object:nil];
The handler for the keyboard appearing event:
- (void)keyboardWasShown:(NSNotification*)aNotification {
    
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    // get the keyboard height
    double keyboardHeight = kbSize.height;
    UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    
    // The calculations are little different for landscape mode.
    if (UIInterfaceOrientationLandscapeLeft == currentOrientation ||UIInterfaceOrientationLandscapeRight == currentOrientation ) {
        keyboardHeight = kbSize.width;
    }
    
    // save the position of the scroll view, so that we can scroll it to its original position when keyboard disappears.
    originalScrollOffset = scroller.contentOffset;

    CGPoint cp = [editView convertPoint:editView.bounds.origin toView:[UIApplicationsharedApplication].keyWindow.rootViewController.view];
    
    cp.y += editView.frame.size.height;
        
    CGRect bounds = [[UIScreen mainScreen] applicationFrame];
    double sh = bounds.size.height;
        
    UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        
    if (UIInterfaceOrientationLandscapeLeft == currentOrientation ||UIInterfaceOrientationLandscapeRight == currentOrientation ) {
        sh = bounds.size.width;
    }

    // scroll if the keyboard is hiding the text view
    if(cp.y > sh - keyboardHeight){
        double sofset = cp.y - (sh - keyboardHeight);
        CGPoint offset = scroller.contentOffset;
        offset.y += sofset;
        scroller.contentOffset = offset;
    }
}

And when the keyboard disappears:
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    // restore the scroll position
    scroller.contentOffset = originalScrollOffset;
}


The above code is used in "Lekh Diagram" ipad app. Lekh Diagrma is a sketch recognition diagramming app.
You can get the Lekh Diagram from app store:
https://itunes.apple.com/us/app/lekh-diagram/id576124115

You can see how content in scrolled when the keyboard appears in the demo of Lekh Diagram:


Learn more about Lekh Diagram: http://www.avabodh.com/lekh

Sunday, January 15, 2012

Drawing and erasing using touch on Android

Drawing/Erasing using touch is a common feature in many mobile phone/tablet based apps. Writing code for this feature is pretty simple for android. Here are steps to do that:
  • add a custom view on which you will draw.
  • process touch event on view.
  • on touch event, record points where touch event occurred.
  • in onDraw method, draw points that were recorded.

Adding a custom view:

We will derive a class from View class for implementing drawing canvas. And we will add this to UI tree. To add this to UITree, create a LinearLayout in which the custom view will be added. The LinearLayout is declared in layout xml as:
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="horizontal"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:id="@+id/drawPanel">
    </LinearLayout>
and from the code, add the custom view to this LinearLayout as:
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        LinearLayout ll = (LinearLayout)findViewById(R.id.drawPanel);
        DrawPanel drawingPanel = new DrawPanel(getApplicationContext());
        ll.addView(drawingPanel);
    }
This code finds the LinearLayout object which was defined in XML and then adds an object of DrawPanel to this. The DrawPanel is the custom View class which is being used for drawing. Here is the implementation of DrawPanel


public class DrawPanel extends View { 
public DrawPanel(Context context) {
  super(context);
  points = new ArrayList();
  strokes = new ArrayList();
  paint = createPaint(Color.GREEN, 8);
 }

 @Override
 public void onDraw(Canvas c){
  super.onDraw(c);
  this.setBackgroundColor(Color.WHITE);
  for(Object obj: strokes){
   drawStroke((ArrayList)obj, c);
  }
  
  drawStroke(points, c);
 }
 
 @Override
 public boolean onTouchEvent(MotionEvent event){
  if(event.getActionMasked() == MotionEvent.ACTION_MOVE){
   points.add(new Point((int)event.getX(), (int)event.getY()));
   invalidate();
  }
  
  if(event.getActionMasked() == MotionEvent.ACTION_UP){
   this.strokes.add(points);
   points = new ArrayList();
  }
  
  return true;
 }
 
 private void drawStroke(ArrayList stroke, Canvas c){
  if (stroke.size() > 0) {
   Point p0 = (Point)stroke.get(0);
   for (int i = 1; i < stroke.size(); i++) {
    Point p1 = (Point)stroke.get(i);
    c.drawLine(p0.x, p0.y, p1.x, p1.y, paint);
    p0 = p1;
   }
  }
 }
 
 private Paint createPaint(int color, float width){
  Paint temp = new Paint();
  temp.setStyle(Paint.Style.STROKE);
  temp.setAntiAlias(true);
  temp.setColor(color);
  temp.setStrokeWidth(width);
  temp.setStrokeCap(Cap.ROUND);
  
  return temp;
 }
 
 private Paint paint;
 private ArrayList points;
 private ArrayList strokes;
}

The above code is for drawing. With a small tweak, erasing can be implemented. While erasing, set the paint color as that of background, that's it!! 

The above code is used in Scratchpad, a drawing app for Android tablets.

Tuesday, January 10, 2012

My first android app: learning+coding+publishing in 5 days


Hey! don't be surprised.  This is not a game like "Angry Birds". Typically, 5 days are not sufficient for a beginner to create a descent app. But my app is not just a "Hello World" app. This is Scratchpad: a simple drawing app. This can be used mostly by kids to draw/erase with touch and can also share the drawing using emails or any other image sharing app. The Scratchpad also has a feature of smoothing the hand-drawn curve which makes it little different from other similar apps.

Here is how this was started: During the new year vacation, I wanted to learn about  Android app development. I got 5 days: 28th Dec to 1st Jan. On the first day, I spent few hours to read about the Android app fundamentals on the Android developer website. I already knew Java, so I did not have to learn a new programing language. After reading the fundamentals, I downloaded few sample projects from internet and started running them. On the 2nd days, I was going through the source code of the samples and running them on emulator. There were many samples to run, so I was not doing any modification to code. I was quickly running those code. At the end of second day, I got confidence that I can now write an app. Then got the idea of a drawing app and then started on this.

I started on development of the drawing app on the evening of second day. Then suddenly I thought that let me release this app on 1st of Jan and make this new year very special. I had only 3 days left (including 1st Jan), I was not sure that I will be able to complete or not.

By the end of 3rd day, I had most of the features working. I was feeling much more confident. But icon work was still not done. Here is the list of things that that I completed:-
  • Drawing using touch
  • Erasing
  • Selecting color
  • Setting pen width
  • Export the drawing as png to Pictures folder, so that it can be viewed in Gallery app.
  • Share the drawing using email or any other sharing app that is installed on device.

I had to struggle a bit for color picker dialog. I could not find any standard Android widget for this. I searched on internet, there were many samples available. I tried few of them and picked one.

On the 4th day morning, I was feeling much more confident. Now I was thinking to add a feature that can differentiate the Scratchpad from other similar apps. So I decided to add a feature of curve smoothing. I already had C++ curve fitting code. Porting the C++ code to Java could take much time. I wanted to wrap-up by the day. So tried java native interface using NDK. Using NDK was straight forward. I integrated the C++ code within few hours.

By now, I was done with all features that I wanted. Now it was time to work upon icons. I searched for free icons on internet and picked some free icons. But I had to edit almost all icons in GIMP.

Now it was 4th day evening. Everything done!! I was very happy!! Now started testing and found a bug!! The bug was in the C++ curve fitting code. It was silently crashing the app. I had no idea what was wrong. Tried the debugger that comes with NDK, but it did not work properly. The NDK build was striping-off the debug symbol even if it was given debug flag. I worked around this by copying the shared object file from obj folder to libs manually after the build. But it did not help. The debugger was reading the debug symbol incorrectly. I was not able to step or print the variable values. However I was able to break the debugger at given function. Now I had two options:- give more time to fix the debugging or create a standalone Linux application or standard Java application and use and test the curve fitting code there. But these options were to take much time. Then I worked around the issue by different way. The issue used to reproduce if the number of points to smooth were very high. If the number of points are very high, then not calling the smoothing was temporary solution. In a typical usage of the app, it was not reproing.

On the last day (1st Jan), I created developer account, signed my app, created screenshots and uploaded my app. After two or three hours, it was available on the Android market.
While publishing the app, I discovered that Indian developer can not publish paid app on android market. I was disappointed by this. Although the Scratchpad was free, I have plan for my next paid app. Now I am considering iOS platform for my future paid app.

On the next day I was very disappointed to see that there were no downloads of this app. Then I shared the the app on reddit (/r/androidapps)  and then the app started getting downloaded. As of now there are 30 downloads of this app.

I wanted to replace one of the screenshot of the app on the android market. It seems there is some bug. From the web interface, it lets to upload/replace screenshot but actually it is not updating.

One more thing that I did not mention yet. The experience of working on emulator is very bad. It is too slow to work on. I was mostly working on a tablet (Asus EEE Pad Transformer). My code was crashing on emulator with older version of android (older then Honeycomb). Because of time constraint and slow emulator experience, I did not get much time to debug the issue and removed the support for older android versions. The Scratchpad works for Honeycomb and newer Android version. I guess, the Scratchpad download would have been more if it supported older version.
Here is android market link to Scratchpad: https://market.android.com/details?id=com.avabodh.scratchpad