root/src/apps/terminal/TerminalLine.h
/*
 * Copyright 2013, Haiku, Inc. All rights reserved.
 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Ingo Weinhold, ingo_weinhold@gmx.de
 *              Siarzhuk Zharski, zharik@gmx.li
 */
#ifndef TERMINAL_LINE_H
#define TERMINAL_LINE_H

#include <GraphicsDefs.h>
#include <SupportDefs.h>

#include "TermConst.h"

#include "UTF8Char.h"


struct Attributes {
        uint32 state;
        uint32 foreground;
        uint32 background;
        uint32 underline;
        int underlineStyle;
        uint32 hyperlink;

        Attributes() : state(0), foreground(0), background(0), underline(0), underlineStyle(0),
                hyperlink(0) {}

        inline void Reset()
        {
                state = 0;
                foreground = 0;
                background = 0;
                underline = 0;
                underlineStyle = 0;
        }

        inline bool IsWidth() const { return (state & A_WIDTH) == A_WIDTH; }
        inline bool IsBold() const { return (state & BOLD) == BOLD; }
        inline bool IsUnder() const { return (state & UNDERLINE) == UNDERLINE; }
        inline bool IsInverse() const { return (state & INVERSE) == INVERSE; }
        inline bool IsOver() const { return (state & OVERLINE) == OVERLINE; }
        inline bool IsHidden() const { return (state & HIDDEN) == HIDDEN; }
        inline bool IsMouse() const { return (state & MOUSE) == MOUSE; }
        inline bool IsForeSet() const { return (state & FORESET) == FORESET; }
        inline bool IsBackSet() const { return (state & BACKSET) == BACKSET; }
        inline bool IsUnderSet() const { return (state & UNDERSET) == UNDERSET; }
        inline bool IsFont() const { return (state & FONT) == FONT; }
        inline bool IsCR() const { return (state & DUMPCR) == DUMPCR; }

        inline void SetDirectForeground(uint8 red, uint8 green, uint8 blue)
        {
                foreground = 0x80000000 | (red << 16) | (green << 8) | blue;
                state &= ~FORECOLOR;
                state |= FORESET;
        }

        inline void SetDirectBackground(uint8 red, uint8 green, uint8 blue)
        {
                background = 0x80000000 | (red << 16) | (green << 8) | blue;
                state &= ~BACKCOLOR;
                state |= BACKSET;
        }

        inline void SetDirectUnderline(uint8 red, uint8 green, uint8 blue)
        {
                underline = 0x80000000 | (red << 16) | (green << 8) | blue;
                state |= UNDERSET;
        }

        inline void SetIndexedForeground(uint32 index)
        {
                state &= ~FORECOLOR;
                state |= FORESET;
                state |= FORECOLORED(index);
                foreground = 0;
        }

        inline void SetIndexedBackground(uint32 index)
        {
                state &= ~BACKCOLOR;
                state |= BACKSET;
                state |= BACKCOLORED(index);
                background = 0;
        }

        inline void SetIndexedUnderline(uint32 index)
        {
                state |= UNDERSET;
                underline = index;
        }

        inline void SetUnder(int style)
        {
                underlineStyle = style;
                state |= UNDERLINE;
        }

        inline void SetHyperlink(uint32 id)
        {
                hyperlink = id;
        }

        inline void UnsetForeground()
        {
                state &= ~FORESET;
                foreground = 0;
        }

        inline void UnsetBackground()
        {
                state &= ~BACKSET;
                background = 0;
        }

        inline void UnsetUnderline()
        {
                state &= ~UNDERSET;
                underline = 0;
        }

        inline void UnsetUnder()
        {
                underlineStyle = 0;
                state &= ~UNDERLINE;
        }

        inline rgb_color
        ForegroundColor(const rgb_color* indexedColors) const
        {
                if ((foreground & 0x80000000) != 0)
                        return make_color((foreground >> 16) & 0xFF,
                                (foreground >> 8) & 0xFF,
                                foreground & 0xFF);
                else
                        return indexedColors[(state & FORECOLOR) >> 16];
        }

        inline rgb_color
        BackgroundColor(const rgb_color* indexedColors) const
        {
                if ((background & 0x80000000) != 0)
                        return make_color((background >> 16) & 0xFF,
                                (background >> 8) & 0xFF,
                                background & 0xFF);
                else
                        return indexedColors[(state & BACKCOLOR) >> 24];
        }

        inline rgb_color
        UnderlineColor(const rgb_color* indexedColors) const
        {
                if ((underline & 0x80000000) != 0)
                        return make_color((underline >> 16) & 0xFF,
                                (underline >> 8) & 0xFF,
                                underline & 0xFF);
                else
                        return indexedColors[underline];
        }

        inline int
        UnderlineStyle() const
        {
                return underlineStyle;
        }

        inline uint32
        Hyperlink() const
        {
                return hyperlink;
        }

        inline Attributes&
        operator&=(uint32 value) { state &= value; return *this; }

        inline Attributes&
        operator|=(uint32 value) { state |= value; return *this; }

        inline uint32
        operator|(uint32 value) { return state | value; }

        inline uint32
        operator&(uint32 value) { return state & value; }

        inline bool
        operator==(const Attributes& other) const
        {
                return state == other.state
                        && foreground == other.foreground
                        && background == other.background
                        && underline == other.underline
                        && underlineStyle == other.underlineStyle
                        && hyperlink == other.hyperlink;
        }

        inline bool
        operator!=(const Attributes& other) const
        {
                return state != other.state
                        || foreground != other.foreground
                        || background != other.background
                        || underline != other.underline
                        || underlineStyle != other.underlineStyle
                        || hyperlink != other.hyperlink;
        }
};


struct TerminalCell {
        UTF8Char                        character;
        Attributes                      attributes;

        inline bool
        operator!=(const Attributes& other) const
        {
                return (attributes.state & CHAR_ATTRIBUTES)
                                != (other.state & CHAR_ATTRIBUTES)
                        || attributes.foreground != other.foreground
                        || attributes.background != other.background
                        || attributes.hyperlink != other.hyperlink;
        }
};


struct TerminalLine {
        uint16                  length;
        bool                    softBreak;      // soft line break
        Attributes              attributes;
        TerminalCell    cells[1];

        inline void Clear()
        {
                Clear(Attributes());
        }

        inline void Clear(size_t count)
        {
                Clear(Attributes(), count);
        }

        inline void Clear(Attributes attr, size_t count = 0)
        {
                length = 0;
                attributes = attr;
                softBreak = false;
                for (size_t i = 0; i < count; i++)
                        cells[i].attributes = attr;
        }
};


struct AttributesRun {
        Attributes      attributes;
        uint16  offset;                 // character offset
        uint16  length;                 // length of the run in characters
};


struct HistoryLine {
        AttributesRun*  attributesRuns;
        uint16                  attributesRunCount;     // number of attribute runs
        uint16                  byteLength : 15;        // number of bytes in the line
        bool                    softBreak : 1;          // soft line break;
        Attributes              attributes;

        AttributesRun* AttributesRuns() const
        {
                return attributesRuns;
        }

        char* Chars() const
        {
                return (char*)(attributesRuns + attributesRunCount);
        }

        int32 BufferSize() const
        {
                return attributesRunCount * sizeof(AttributesRun) + byteLength;
        }
};


#endif  // TERMINAL_LINE_H