void idListWindow::UpdateList() { idStr str, strName; listItems.Clear(); for( int i = 0; i < MAX_LIST_ITEMS; i++ ) { if( gui->State().GetString( va( "%s_item_%i", listName.c_str(), i ), "", str ) ) { if( str.Length() ) { listItems.Append( str ); } } else { break; } } float vert = GetMaxCharHeight(); int fit = textRect.h / vert; if( listItems.Num() < fit ) { scroller->SetRange( 0.0f, 0.0f, 1.0f ); } else { scroller->SetRange( 0.0f, ( listItems.Num() - fit ) + 1.0f, 1.0f ); } SetCurrentSel( gui->State().GetInt( va( "%s_sel_0", listName.c_str() ) ) ); float value = scroller->GetValue(); if( value > listItems.Num() - 1 ) { value = listItems.Num() - 1; } if( value < 0.0f ) { value = 0.0f; } scroller->SetValue( value ); top = value; typedTime = 0; clickTime = 0; typed = ""; }
void idEditWindow::Draw( int time, float x, float y ) { idVec4 color = foreColor; UpdateCvar( true ); int len = text.Length(); if ( len != lastTextLength ) { scroller->SetValue( 0.0f ); EnsureCursorVisible(); lastTextLength = len; } float scale = textScale; idStr pass; const char* buffer; if ( password ) { const char* temp = text; for ( ; *temp; temp++ ) { pass += "*"; } buffer = pass; } else { buffer = text; } if ( cursorPos > len ) { cursorPos = len; } idRectangle rect = textRect; rect.x -= paintOffset; rect.w += paintOffset; if ( wrap && scroller->GetHigh() > 0.0f ) { float lineHeight = GetMaxCharHeight( ) + 5; rect.y -= scroller->GetValue() * lineHeight; rect.w -= sizeBias; rect.h = ( breaks.Num() + 1 ) * lineHeight; } if ( hover && !noEvents && Contains(gui->CursorX(), gui->CursorY()) ) { color = hoverColor; } else { hover = false; } if ( flags & WIN_FOCUS ) { color = hoverColor; } dc->DrawText( buffer, scale, 0, color, rect, wrap, (flags & WIN_FOCUS) ? cursorPos : -1); }
void idEditWindow::EnsureCursorVisible() { if( readonly ) { cursorPos = -1; } else if( maxChars == 1 ) { cursorPos = 0; } if( !dc ) { return; } SetFont(); if( !wrap ) { int cursorX = 0; if( password ) { cursorX = cursorPos * dc->CharWidth( '*', textScale ); } else { int i = 0; while( i < text.Length() && i < cursorPos ) { if( idStr::IsColor( &text[i] ) ) { i += 2; } else { cursorX += dc->CharWidth( text[i], textScale ); i++; } } } int maxWidth = GetMaxCharWidth( ); int left = cursorX - maxWidth; int right = ( cursorX - textRect.w ) + maxWidth; if( paintOffset > left ) { // When we go past the left side, we want the text to jump 6 characters paintOffset = left - maxWidth * 6; } if( paintOffset < right ) { paintOffset = right; } if( paintOffset < 0 ) { paintOffset = 0; } scroller->SetRange( 0.0f, 0.0f, 1.0f ); } else { // Word wrap breaks.Clear(); idRectangle rect = textRect; rect.w -= sizeBias; dc->DrawText( text, textScale, textAlign, colorWhite, rect, true, ( flags & WIN_FOCUS ) ? cursorPos : -1, true, &breaks ); int fit = textRect.h / ( GetMaxCharHeight() + 5 ); if( fit < breaks.Num() + 1 ) { scroller->SetRange( 0, breaks.Num() + 1 - fit, 1 ); } else { // The text fits completely in the box scroller->SetRange( 0.0f, 0.0f, 1.0f ); } if( forceScroll ) { scroller->SetValue( breaks.Num() - fit ); } else if( readonly ) { } else { cursorLine = 0; for( int i = 1; i < breaks.Num(); i++ ) { if( cursorPos >= breaks[i] ) { cursorLine = i; } else { break; } } int topLine = idMath::Ftoi( scroller->GetValue() ); if( cursorLine < topLine ) { scroller->SetValue( cursorLine ); } else if( cursorLine >= topLine + fit ) { scroller->SetValue( ( cursorLine - fit ) + 1 ); } } } }
const char *idListWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) { // need to call this to allow proper focus and capturing on embedded children const char *ret = idWindow::HandleEvent(event, updateVisuals); float vert = GetMaxCharHeight(); int numVisibleLines = textRect.h / vert; int key = event->evValue; if ( event->evType == SE_KEY ) { if ( !event->evValue2 ) { // We only care about key down, not up return ret; } if ( key == K_MOUSE1 || key == K_MOUSE2 ) { // If the user clicked in the scroller, then ignore it if ( scroller->Contains(gui->CursorX(), gui->CursorY()) ) { return ret; } } if ( ( key == K_ENTER || key == K_KP_ENTER ) ) { RunScript( ON_ENTER ); return cmd; } if ( key == K_MWHEELUP ) { key = K_UPARROW; } else if ( key == K_MWHEELDOWN ) { key = K_DOWNARROW; } if ( key == K_MOUSE1) { if (Contains(gui->CursorX(), gui->CursorY())) { int cur = ( int )( ( gui->CursorY() - actualY - pixelOffset ) / vert ) + top; if ( cur >= 0 && cur < listItems.Num() ) { if ( multipleSel && idKeyInput::IsDown( K_CTRL ) ) { if ( IsSelected( cur ) ) { ClearSelection( cur ); } else { AddCurrentSel( cur ); } } else { if ( IsSelected( cur ) && ( gui->GetTime() < clickTime + doubleClickSpeed ) ) { // Double-click causes ON_ENTER to get run RunScript(ON_ENTER); return cmd; } SetCurrentSel( cur ); clickTime = gui->GetTime(); } } else { SetCurrentSel( listItems.Num() - 1 ); } } } else if ( key == K_UPARROW || key == K_PGUP || key == K_DOWNARROW || key == K_PGDN ) { int numLines = 1; if ( key == K_PGUP || key == K_PGDN ) { numLines = numVisibleLines / 2; } if ( key == K_UPARROW || key == K_PGUP ) { numLines = -numLines; } if ( idKeyInput::IsDown( K_CTRL ) ) { top += numLines; } else { SetCurrentSel( GetCurrentSel() + numLines ); } } else { return ret; } } else if ( event->evType == SE_CHAR ) { if ( !idStr::CharIsPrintable(key) ) { return ret; } if ( gui->GetTime() > typedTime + 1000 ) { typed = ""; } typedTime = gui->GetTime(); typed.Append( key ); for ( int i=0; i<listItems.Num(); i++ ) { if ( idStr::Icmpn( typed, listItems[i], typed.Length() ) == 0 ) { SetCurrentSel( i ); break; } } } else { return ret; } if ( GetCurrentSel() < 0 ) { SetCurrentSel( 0 ); } if ( GetCurrentSel() >= listItems.Num() ) { SetCurrentSel( listItems.Num() - 1 ); } if ( scroller->GetHigh() > 0.0f ) { if ( !idKeyInput::IsDown( K_CTRL ) ) { if ( top > GetCurrentSel() - 1 ) { top = GetCurrentSel() - 1; } if ( top < GetCurrentSel() - numVisibleLines + 2 ) { top = GetCurrentSel() - numVisibleLines + 2; } } if ( top > listItems.Num() - 2 ) { top = listItems.Num() - 2; } if ( top < 0 ) { top = 0; } scroller->SetValue(top); } else { top = 0; scroller->SetValue(0.0f); } if ( key != K_MOUSE1 ) { // Send a fake mouse click event so onAction gets run in our parents const sysEvent_t ev = sys->GenerateMouseButtonEvent( 1, true ); idWindow::HandleEvent(&ev, updateVisuals); } if ( currentSel.Num() > 0 ) { for ( int i = 0; i < currentSel.Num(); i++ ) { gui->SetStateInt( va( "%s_sel_%i", listName.c_str(), i ), currentSel[i] ); } } else { gui->SetStateInt( va( "%s_sel_0", listName.c_str() ), 0 ); } gui->SetStateInt( va( "%s_numsel", listName.c_str() ), currentSel.Num() ); return ret; }
void idListWindow::Draw(int time, float x, float y) { idVec4 color; idStr work; int count = listItems.Num(); idRectangle rect = textRect; float scale = textScale; float lineHeight = GetMaxCharHeight(); float bottom = textRect.Bottom(); float width = textRect.w; if ( scroller->GetHigh() > 0.0f ) { if ( horizontal ) { bottom -= sizeBias; } else { width -= sizeBias; rect.w = width; } } if ( noEvents || !Contains(gui->CursorX(), gui->CursorY()) ) { hover = false; } for (int i = top; i < count; i++) { if ( IsSelected( i ) ) { rect.h = lineHeight; dc->DrawFilledRect(rect.x, rect.y + pixelOffset, rect.w, rect.h, borderColor); if ( flags & WIN_FOCUS ) { idVec4 color = borderColor; color.w = 1.0f; dc->DrawRect(rect.x, rect.y + pixelOffset, rect.w, rect.h, 1.0f, color ); } } rect.y ++; rect.h = lineHeight - 1; if ( hover && !noEvents && Contains(rect, gui->CursorX(), gui->CursorY()) ) { color = hoverColor; } else { color = foreColor; } rect.h = lineHeight + pixelOffset; rect.y --; if ( tabInfo.Num() > 0 ) { int start = 0; int tab = 0; int stop = listItems[i].Find('\t', 0); while ( start < listItems[i].Length() ) { if ( tab >= tabInfo.Num() ) { common->Warning( "idListWindow::Draw: gui '%s' window '%s' tabInfo.Num() exceeded", gui->GetSourceFile(), name.c_str() ); break; } listItems[i].Mid(start, stop - start, work); rect.x = textRect.x + tabInfo[tab].x; rect.w = (tabInfo[tab].w == -1) ? width - tabInfo[tab].x : tabInfo[tab].w; dc->PushClipRect( rect ); if ( tabInfo[tab].type == TAB_TYPE_TEXT ) { dc->DrawText(work, scale, tabInfo[tab].align, color, rect, false, -1); } else if (tabInfo[tab].type == TAB_TYPE_ICON) { const idMaterial **hashMat; const idMaterial *iconMat; // leaving the icon name empty doesn't draw anything if ( work[0] != '\0' ) { if ( iconMaterials.Get(work, &hashMat) == false ) { iconMat = declManager->FindMaterial("_default"); } else { iconMat = *hashMat; } idRectangle iconRect; iconRect.w = tabInfo[tab].iconSize.x; iconRect.h = tabInfo[tab].iconSize.y; if(tabInfo[tab].align == idDeviceContext::ALIGN_LEFT) { iconRect.x = rect.x; } else if (tabInfo[tab].align == idDeviceContext::ALIGN_CENTER) { iconRect.x = rect.x + rect.w/2.0f - iconRect.w/2.0f; } else if (tabInfo[tab].align == idDeviceContext::ALIGN_RIGHT) { iconRect.x = rect.x + rect.w - iconRect.w; } if(tabInfo[tab].valign == 0) { //Top iconRect.y = rect.y + tabInfo[tab].iconVOffset; } else if(tabInfo[tab].valign == 1) { //Center iconRect.y = rect.y + rect.h/2.0f - iconRect.h/2.0f + tabInfo[tab].iconVOffset; } else if(tabInfo[tab].valign == 2) { //Bottom iconRect.y = rect.y + rect.h - iconRect.h + tabInfo[tab].iconVOffset; } dc->DrawMaterial(iconRect.x, iconRect.y, iconRect.w, iconRect.h, iconMat, idVec4(1.0f,1.0f,1.0f,1.0f), 1.0f, 1.0f); } } dc->PopClipRect(); start = stop + 1; stop = listItems[i].Find('\t', start); if ( stop < 0 ) { stop = listItems[i].Length(); } tab++; } rect.x = textRect.x; rect.w = width; } else { dc->DrawText(listItems[i], scale, 0, color, rect, false, -1); } rect.y += lineHeight; if ( rect.y > bottom ) { break; } } }