Proper 1D BlockGrid

Hi all, if I've tagged you here it's because I thought you might be interested in providing feedback in either the code review sense or just the concept. No worries if you're not interested, you can mute notifications on this issue at the bottom of the screen.

As of ipythonblocks 1.5 there's no such thing as a 1D grid, they are all 2D, so doing something like this returns a 2D grid:

```python
grid = BlockGrid(5, 5)
grid[0]  # returns a 2D grid
```

And further, that means attempts at nested-list style indexing doesn't work as expected because indexing into even a height=1 grid just returns the whole grid again:

```python
grid = BlockGrid(5, 5)
grid[0][0]  # returns the whole first row as a 2D grid over and over again
```

On solution would be to just totally disable single-digit indexing and require all indices to be explicitly 2D, e.g. `grid[0, 0]` or `grid[3, :]` but no `grid[0][0]` or `grid[3]`. This is the approach taken by the `ImageGrid` class.

In this PR, though, I have implemented 1D grids on the `BlockGrid` grid class, allowing things like this:

```python
grid = BlockGrid(5)
grid[0]  # returns a single Block
grid[1:4]  # returns a new 1D BlockGrid

grid = BlockGrid(5, 5)
grid[0]  # returns a 1D BlockGrid
grid[0][0]  # returns a single Block
```

There are some gotchas with this implementation in addition to the little bit of complexity added by the decision code to handle 1D vs. 2D cases:

To simplify the implementation it was easiest to keep 2D lookup available on 1D grids, so `grid[0, 0]` still works on a 1D grid. This is mostly because the `__getitem__` method is currently the only place that sets the `.row` and `.col` attributes on the returned `Block` instances. If I duplicated that in the iter and repr methods along with some dimensionality logic it should be possible to restrict 1D grids to 1D indexing. (This would honestly not be that hard, I think.)

On a 2D grid `grid[3, 1]` and `grid[3][1]` return blocks with different `.row` and `.col` attributes because `grid[3]` first returns 1D grid for which every block will have row=0.

So, does the bit of added complexity for 1D grids seem worth it, or should `BlockGrid` just require explicit 2D indexing all the time? Thanks for looking.

Tagging people:
@iguananaut @wking @gvwilson @picken19 @catherinedevlin