root/src/apps/charactermap/UnicodeBlockView.cpp
/*
 * Copyright 2009, Axel Dörfler, axeld@pinc-software.de.
 * Distributed under the terms of the MIT License.
 */


#include "UnicodeBlockView.h"

#include <ControlLook.h>

#include <stdio.h>
#include <string.h>

#include "UnicodeBlocks.h"


BlockListItem::BlockListItem(const char* label, uint32 blockIndex)
        : BStringItem(label),
        fBlockIndex(blockIndex)
{
}


//      #pragma mark -


UnicodeBlockView::UnicodeBlockView(const char* name)
        : BListView(name),
        fBlocks(kNumUnicodeBlocks),
        fShowPrivateBlocks(false),
        fShowContainedBlocksOnly(false)
{
        _CreateBlocks();
}


UnicodeBlockView::~UnicodeBlockView()
{
}


void
UnicodeBlockView::SetFilter(const char* filter)
{
        fFilter = filter;
        _UpdateBlocks();
}

void
UnicodeBlockView::SetCharacterFont(const BFont& font)
{
        fCharacterFont = font;
        fUnicodeBlocks = fCharacterFont.Blocks();
        _UpdateBlocks();
}


void
UnicodeBlockView::ShowPrivateBlocks(bool show)
{
        if (fShowPrivateBlocks == show)
                return;

        fShowPrivateBlocks = show;
        _UpdateBlocks();
}


void
UnicodeBlockView::ShowContainedBlocksOnly(bool show)
{
        if (fShowContainedBlocksOnly == show)
                return;

        fShowContainedBlocksOnly = show;
        _UpdateBlocks();
}


bool
UnicodeBlockView::IsShowingBlock(int32 blockIndex) const
{
        if (blockIndex < 0 || blockIndex >= (int32)kNumUnicodeBlocks)
                return false;

        if (!fShowPrivateBlocks && kUnicodeBlocks[blockIndex].private_block)
                return false;

        // The reason for two checks is BeOS compatibility.
        // The first one checks for unicode blocks as defined by Be,
        // but there are only 71 such blocks.
        // The rest of the blocks (denoted by kNoBlock) need to
        // be queried by searching for the start and end codepoints
        // via the IncludesBlock method.
        if (fShowContainedBlocksOnly) {
                if (kUnicodeBlocks[blockIndex].block != kNoBlock)
                        return (fUnicodeBlocks & kUnicodeBlocks[blockIndex].block) != kNoBlock;

                if (!fCharacterFont.IncludesBlock(
                                kUnicodeBlocks[blockIndex].start,
                                kUnicodeBlocks[blockIndex].end))
                        return false;
        }

        return true;
}


void
UnicodeBlockView::_UpdateBlocks()
{
        MakeEmpty();

        for (int32 i = 0; i < fBlocks.CountItems(); i++) {
                if (fFilter.Length() != 0) {
                        if (strcasestr(kUnicodeBlocks[i].name, fFilter.String()) == NULL)
                                continue;
                }

                AddItem(fBlocks.ItemAt(i));

                fBlocks.ItemAt(i)->SetEnabled(IsShowingBlock(i));
        }
}


void
UnicodeBlockView::_CreateBlocks()
{
        float minWidth = 0;
        for (uint32 i = 0; i < kNumUnicodeBlocks; i++) {
                BlockListItem* item = new BlockListItem(kUnicodeBlocks[i].name, i);
                fBlocks.AddItem(item);

                float width = StringWidth(item->Text());
                if (minWidth < width)
                        minWidth = width;
        }

        minWidth += 2 * be_control_look->DefaultLabelSpacing();
        SetExplicitMinSize(BSize(minWidth / 2, 32));
        SetExplicitMaxSize(BSize(minWidth, B_SIZE_UNSET));

        _UpdateBlocks();
}


void
UnicodeBlockView::SelectBlockForCharacter(uint32 character)
{
        // find block containing the character
        int32 blockNumber = BlockForCharacter(character);

        if (blockNumber >= 0) {
                BlockListItem* block = fBlocks.ItemAt(blockNumber);

                int32 blockIndex = IndexOf(block);

                if (blockIndex >= 0) {
                        Select(blockIndex);
                        ScrollToSelection();
                }
        }
}