Re[3]: Rsdn.Editor
От: alsemm Россия  
Дата: 18.01.06 13:17
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, <Аноним>, Вы писали:


А>>У меня парочка мыслей появилась после прочтения статьи и беглово знакомства с исходниками:

А>>1. Зачем делать word wrap для строк которые не видны на экране? Лишняя работа.

VD>Чтобы сделать точный скролинг и точное отображение позиции в документе.

Вернее чтобы упростить реализацию этих функций

А>>2. Для адресации позиции в тексте достаточно знать смещение символа от начала текста, а уж строку которой принадлежит символ и смещение в строке можно расчитать.


VD>И каждый раз бегать по тексту рассчитывая строку? А смысл? Тормоза от этого конечно увеличатся, а вот бенефиты...

Если юзать string[] для хранения текста, то да, смысла нет, не спорю.
...
VD>Как-то проблем с масштабируемостью я пока не видел. Как и ее необходимости. Поясни, плиз, о чем речь.
Загрузили в редактор большой текст и стали его с головы редактировать. Ограничения стурктуры данных (в данном случае string[]) не будут видны пока мощности железа хватает, но рано или поздно они вылезут. Вообще IMHO использование Position<Document> для адресации сомволов очень напоминает старничную память с кошмариками в виде long и short pointer-ов.
...
VD>1. Так плохой идеей было использовать дотнетный Font. Это не позволяет менять в стилях отдельные атрибуты шрифта. Например, чтобы сделать жирным ключевые слова. Это же не дает реализовать простое масштабирование шрифтов. Мне очень нравится как в Сцинтиле или ИЕ можно менять размер ширфтов просто покрутив колесико мыши удерживая при этом Ctrl.
Думаю это не проблема шрифта, а не совсем удачный дизайн класса Style. Если пользователи захотят что-то большее кроме как рисовать вместо текста картинки? Например обводить подстроку в рамку. Что делать будете? Добавлять поле _drawRectAroundText в Style? IMHO коряво.

Я сам счас редактор делаю. Вот как раскраска у меня задизайнена:
class TextStyle
{
public:
    COLORREF fgColor;
    COLORREF bgColor;    
    HFONT    font;
public:
    TextStyle(): fgColor(CLR_INVALID), bgColor(CLR_INVALID), font(0) {}
};

class IDecoratorListener;
class IDecoratedSubstring;

class IDecorator
{
public:
    virtual ~IDecorator() {}
public:
    virtual void
    decorate(
        unsigned            line, 
        const char_type*    str,
        unsigned            len, 
        IDecoratorListener& dl) const = 0;
};

class IDecoratorListener
{
public:
    virtual ~IDecoratorListener() {}
public:
    virtual bool
    onSubstringDecorated(
        unsigned                    line, 
        const char_type*            str,
        unsigned                    strLen, 
        const char_type*            substr,
        unsigned                    substrLen, 
        const TextStyle&            ts) = 0;

    virtual bool
    onSubstringDecorated(
        unsigned                    line,
        const char_type*            str,
        unsigned                    strLen, 
        const char_type*            substr,
        unsigned                    substrLen, 
        const IDecoratedSubstring&  ds) = 0;
};

class IDecoratedSubstring
{
public:
    virtual ~IDecoratedSubstring() {}
public:
    virtual unsigned 
    getWidth(unsigned width) const = 0;

    virtual unsigned 
    getHeight(unsigned height) const = 0;

    virtual FONT
    getFont() const = 0;

    virtual void
    paint(HDC g, unsigned width, unsigned height) const = 0;
};


Вот, например, как можно сделать изменение размера шрифта "как в Сцинтиле или ИЕ":
class FontChangeDecorator : public IDecorator, IDecoratorListener
{
    IDecorator*         decorator_;
    IDecoratorListener* listener_;
public:
    FontChangeDecorator(IDecorator* decorator): decorator_(decorator) {}
public:
    virtual void
    decorate(
        unsigned            line, 
        const char_type*    str,
        unsigned            len, 
        IDecoratorListener& dl) const
    {
        // запомнить текущее значение listener_, чтобы восстановить его в случае рекурсивного 
        // вызова FontChangeDecorator::decorate
        IDecoratorListener* l = listener_;
        // подменить листенер
        listener_ = dl;        
        decorator_->decorate(line, str, len, *this);
        // восстановить листенер 
        listener_ = l;
    }
private:
    virtual bool
    onSubstringDecorated(
        unsigned         line, 
        const char_type* str,
        unsigned         strLen, 
        const char_type* substr,
        unsigned         substrLen, 
        const TextStyle& ts)
    {
        HDC dc = getTempDC(); // каким-то образом получить HDC
        ::SelectFont(dc, ts.font);
        TEXTMETRICS tm;
        ::GetTextMetrics(dc, &tm);
        LOGFONT lf = textMetrics2LogFont(tm);  // как-то сконвертировали
        lf.height += (lf.height * 10) / 100; // увеличить шрифт на 10%
        
        TextStyle newTs(ts);
        newTs.font = ::CreateFontIndirect(lf);

        // передать в листенер измененный шрифт
        listener_.onSubstringDecorated(line, str, strLen, substr, substrLen, newTs);
    }
};


Использование FontChangeDecorator:
void
setFontChangeDecorator(HWND hwnd /* хендл на окно моего редактора */)
{
    IDecorator* d  = ::SendMessage(hwnd, MYEDITOR_MSG_GETDECORATOR, 0, 0);
    IDecorator* d2 = new FontChangeDecorator(d);

   ::SendMessage(hwnd, MYEDITOR_MSG_SETDECORATOR, d2, 0)
}


Редактор дергает IDecorator::decorate каждый раз когда надо отрисовать строку текста передавая свои реализации интерфейса IDecoratorListener. Есть реализации IDecoratorListener-а которые высчитывают ширину подстроки/целой строки, высоту ну и т.д. Word wrap так же сделан через IDecoratorListener.
Бенефиты такого подхода:
1. декоратор дергается только для тех строк которые видны на экране — не надо мучать процессор лишней работой;
2. легко сделать кэш строк обработанных декоратором, т.к. для этого достаточно просто написать еще одну реализацию IDecoratorListener;
3. Визуализация текста не ограничена рисованием текста или рисованием картинки вместо текста, т.к. реализация IDecoratedSubstring ограничена только фантазией юзверя (в разумных пределах конечно ;
4. декораторы можно комбинировать. Пример — FontChangeDecorator который изменяет результаты разбора уже существующего декоратора.

Алексей
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.